1. 程式人生 > >NOIP模板複習——基礎演算法

NOIP模板複習——基礎演算法

二分

求滿足條件的最小值

while(l<r)
{
	int mid=(l+r)>>1;
	if(check(mid))  r=mid;
	else  l=mid+1;
}

求滿足條件的最大值

while(l<r)
{
	int mid=(l+r+1)>>1;
	if(check(mid))  l=mid;
	else  r=mid-1;
}

實數域上的二分(可以用 e p

s eps ,也可以二分 100 100 次)

while(l+eps<r)
{
	double mid=(l+r)/2;
	if(check(mid))  r=mid;
	else  l=mid;
}

三分

求單峰函式最大值

while(r-l>=
eps) { m1=l+(r-l)/3; m2=r-(r-l)/3; if(f(m2)-f(m1)>=eps) l=m1; else r=m2; }

求最小值和求最大值差不多,注意一下好點和壞點之前的關係就行了

逆序對

分治+歸併排序

long long merge(int l,int r,int mid)
{
	long long ans=0;
	int i,b1=0,c1=0,b2=1,c2=1;
	for(i=l;i<=mid;++i)  b[++b1]=a[i];
	for(i=mid+1;i<=r;++i)  c[++c1]=a[i];
	for
(i=l;i<=r;++i) { if(b1>=b2&&(c1+1==c2||b[b2]<=c[c2])) a[i]=b[b2++]; else { a[i]=c[c2++]; ans+=b1-b2+1; } } return ans; } long long solve(int l,int r) { if(l==r) return 0; int mid=(l+r)>>1; long long ans=0; ans+=solve(l,mid); ans+=solve(mid+1,r); ans+=merge(l,r,mid); return ans; }

樹狀陣列(只貼最核心的三行,其他的都是樹狀陣列基本操作)

for(i=1;i<=n;++i)
{
	scanf("%d",&x);
	add(x,1);
	ans+=i-sum(x);
}

進位制轉換

十進位制轉其他進位制( x x 為原十進位制數, n n 為要轉換的進位制)

int pos=0;
while(x!=0)
{
	a[++pos]=x%n;
	x/=n;
}
for(i=pos;i;--i)
{
	if(a[i]>10)  printf("%c",a[i]-10+'A');
	else  printf("%d",a[i]);
}

其他進位制轉十進位制( a a 陣列存的是原來的進位制數,下標從 1 1 開始, n n 為原來的進位制, x x 是轉換後的十進位制數)

for(i=1;i<=l;++i)
{
	if(a[i]>='0'&&a[i]<='9')  s=a[i]-'0';
	else  s=a[i]-'A'+10;
	x=x*n+s;
}

離散化

a a 陣列是離散化後的陣列,起初所有的 a i = b i a_i=b_i

sort(b+1,b+n+1);
int m=unique(b+1,b+n+1)-(b+1);
for(i=1;i<=n;++i)
    a[i]=lower_bound(b+1,b+m+1,a[i])-b;

中位數

可以直接用 nth_element 實現

if(n&1)
{
	nth_element(a+1,a+n/2+1,a+n+1);
	return a[n/2+1];
}
else
{
	double x;
	nth_element(a+1,a+n/2,a+n+1),x=a[n/2];
	nth_element(a+1,a+n/2+1,a+n+1),x+=a[n/2+1];
	x/=2;
	return x;
}