1. 程式人生 > >[NOIP專題總結]基礎演算法

[NOIP專題總結]基礎演算法

一.快速運算

快速冪:二進位制位拆分的思想

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.減少不必要的列舉

列舉可以用遞迴,遞推,位運算,迴圈等方式來實現

四.字首和 O(n)O(n)預處理,O(1)O(1)查詢區間和 拓展: 1.差分字首和POJ3263 2.二維字首和

五.遞迴 在函式中呼叫它本身的操作 可以實現一些迴圈無法實現(或者很難實現)的列舉 例題:

POJ2083

六.分治 二分: 單調區間內O(logN)O(logN)查詢某個值的演算法 有二分答案,二分查詢兩種常見形式 二分答案:常見於“最大最小”這類問題,先確定答案範圍(上下界)然後二分出答案的預估值,再驗證是否合法,然後對上下界作出適當調整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.O(n2)O(n^2)排序:用的很少 2.快速排序:c++選手常用sort實現 3.歸併排序:可求逆序對 4.桶排序:計數時常用

離散化: 用map或者陣列實現,便於桶排序等演算法統計

O(n)O(n)k大數: 排序時,統計左半部分的大於基準值的數個數,然後和k比較並且下一次操作只往左或右邊操作

八.倍增 先求解以2的整數次冪為底數的答案,再拼合起來,複雜度logn 應用:女選手 求LCA,ST表

九.貪心 每一步操作都選擇最優的情況,是重要的得分演算法