[NOIP專題總結]基礎演算法
阿新 • • 發佈:2018-12-19
一.快速運算
快速冪:二進位制位拆分的思想
const ll mod=1000000007;
ll ksm(ll a,ll b){
ll ans=1;
for(;b;b>>=1){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
}
return ans;
}
快速乘:類似快速冪
const ll mod=1000000007;
ll ksm(ll a,ll b){
ll ans=0;
for(;b;b>>=1){
if(b&1) ans=(ans+a)%mod;
a=a*2%mod;
}
return ans;
}
二:位運算 快速swap:
void swap(int x,int y){x^=y,y^=x,x^=y;}
lowbit取位:
#define lowbit(x) x&-x;
*運算子優先順序(升序): 加減 移位 比較大小 與 異或 或
三.列舉 列舉的幾個要點: 1.規劃好要列舉的東西 2.減少不必要的列舉
列舉可以用遞迴,遞推,位運算,迴圈等方式來實現
四.字首和 預處理,查詢區間和 拓展: 1.差分字首和POJ3263 2.二維字首和
五.遞迴
在函式中呼叫它本身的操作
可以實現一些迴圈無法實現(或者很難實現)的列舉
例題: POJ2083
六.分治 二分: 單調區間內查詢某個值的演算法 有二分答案,二分查詢兩種常見形式 二分答案:常見於“最大最小”這類問題,先確定答案範圍(上下界)然後二分出答案的預估值,再驗證是否合法,然後對上下界作出適當調整POJ2018 二分查詢幾種形式:
//單調遞增序列a中查詢>=x的數中最小的一個(即x或x的後繼)
while(l<r)
{
int mid=(l+r)/2;
if(a[mid]>=x)
r=mid;
else
l=mid-1;
}
return a[l];
//單調遞增序列a中查詢<=x的數中最大的一個(即x或x的前驅)
while(l<r)
{
int mid=(l+r+1)/2;
if(a[mid]<=x)
l=mid;
else
r=mid-1;
}
return a[l];
//實數域上的二分
while(l+1e-5<r)
{
double mid=(l+r)/2;
if(calc(mid))
r=mid;
else
l=mid;
}
//實數:二分100次
for(int i=0;i<100;i++)
{
double mid=(l+r)/2;
if(calc(mid))
r=mid;
else
l=mid;
}
拓展:三分
分治: 分而治之,將問題分為多個部,分別求解後合起來統計答案 經典例題:POJ3714
七.排序 1.排序:用的很少 2.快速排序:c++選手常用sort實現 3.歸併排序:可求逆序對 4.桶排序:計數時常用
離散化: 用map或者陣列實現,便於桶排序等演算法統計
k大數: 排序時,統計左半部分的大於基準值的數個數,然後和k比較並且下一次操作只往左或右邊操作
八.倍增
先求解以2的整數次冪為底數的答案,再拼合起來,複雜度logn
應用:女選手 求LCA,ST表
九.貪心 每一步操作都選擇最優的情況,是重要的得分演算法