NOIP复习提纲(持续更新)

1.LCA 预处理(O(nlogn)) 单次查找O(logn)
NKOJ2447

#include
#include
#include
using namespace std;
int n,s,m;
int End[10010],Last[10010],Next[10010];
int deep[10010];
int f[10010][20];
int du[10010];
void deal_first(int u,int father)
{
	deep[u]=deep[father]+1;
	for(int i=0;i<=s;i++)
	f[u][i+1]=f[f[u][i]][i];
	for(int i=Last[u];i;i=Next[i])
	{
		f[End[i]][0]=u;
		deal_first(End[i],u);
	}
}
int LCA(int x,int y)
{
	if(deep[x]=0;i--)
	{
		if(deep[f[x][i]]>=deep[y])
		x=f[x][i];
		if(x==y) return x;
		if(deep[x]==deep[y]) break;
	}
	for(int i=s;i>=0;i--)
	{
		if(f[x][i]!=f[y][i])
		{
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
	
}
int main()
{
	int a,b,x,y;
	scanf("%d",&n);
	s=ceil(log2(n));
	for(int i=1;i

2.ST表 预处理(nlogn) 单次询问O(1)
luogu3865

#include
#include
using namespace std;
int n,q,a[100010],p,f[100010][20];
int log[100010];
int main()
{
    scanf("%d%d",&n,&q);
    log[0]=-1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        f[i][0]=a[i];
        log[i]=log[i>>1]+1;
    }
    for(int i=1;i<=log[n];i++)
    {
        for(int j=1;j+(1<

3.树状数组 单次修改O(logn) 单次查询O(logn)
luogu3374

#include
using namespace std;
int n,m;
int a[500010];
int c[500010];
int lowbit(int x)
{
	return x&(-x);
}
void modify(int x,int y)
{
	for(;x<=n;x+=lowbit(x)) c[x]+=y;
}
int getsum(int x)
{
	int ans=0;
	for(;x>=1;x-=lowbit(x)) ans+=c[x];
	return ans;
}
int main()
{
	int k,x,y;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]),modify(i,a[i]);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&k,&x,&y);
		if(k==1)
		modify(x,y);
		else
		printf("%d\n",getsum(y)-getsum(x-1));
	}
	return 0;
}

4.线段树
(1).单点修改,区间查询 单次修改O(logn) 单次查询O(logn)
LOJ130

#include
#define ll long long
using namespace std;
ll sum[4000010];
int n,q;
ll a[1000010];
void biuldtree(int p,int l,int r)
{
	if(l==r)
	{
		sum[p]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	biuldtree(p<<1,l,mid);
	biuldtree(p<<1|1,mid+1,r);
	sum[p]=sum[p<<1]+sum[p<<1|1];
}
void change(int p,int l,int r,int x,int y)
{
	if(l==r&&l==x)
	{
		sum[p]+=(ll)y;
		return;
	}
	if(l>x||r>1;
	change(p<<1,l,mid,x,y);
	change(p<<1|1,mid+1,r,x,y);
	sum[p]=sum[p<<1]+sum[p<<1|1];
}
ll Ask(int p,int l,int r,int x,int y)
{
	if(x>r||y=r) return sum[p];
	int mid=(l+r)>>1;
	ll lsum,rsum;
	lsum=Ask(p<<1,l,mid,x,y);
	rsum=Ask(p<<1|1,mid+1,r,x,y);
	return lsum+rsum;
}
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	biuldtree(1,1,n);
	int k,x,y;
	while(q--)
	{
		scanf("%d%d%d",&k,&x,&y);
		if(k==1)
		{
			change(1,1,n,x,y);
		}
		else
		{
			printf("%lld\n",Ask(1,1,n,x,y));
		}
	}
	return 0;
}

(2).区间修改,区间查询 单次修改O(logn) 单次查询O(logn)
LOJ132

#include
#define ll long long
using namespace std;
int n,q;
ll a[1000010];
ll Lazy[4000010],sum[4000010];
void biuldtree(int p,int l,int r)
{
    if(l==r)
    {
        sum[p]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    biuldtree(p<<1,l,mid);
    biuldtree(p<<1|1,mid+1,r);
    sum[p]=sum[p<<1]+sum[p<<1|1];
}
void pushdown(int p,int l,int r)
{
    int mid=(l+r)>>1;
    Lazy[p<<1]+=Lazy[p];
    sum[p<<1]+=(ll)(mid-l+1)*Lazy[p];
    Lazy[p<<1|1]+=Lazy[p];
    sum[p<<1|1]+=(ll)(r-mid)*Lazy[p];
    Lazy[p]=0;
}
void change(int p,int l,int r,int x,int y,int v)
{
    if(x>r||y=r)
    {
        Lazy[p]+=(ll)v;
        sum[p]+=(ll)(r-l+1)*v;
        return;
    }
    if(Lazy[p]) pushdown(p,l,r);
    int mid=(l+r)>>1;
    change(p<<1,l,mid,x,y,v);
    change(p<<1|1,mid+1,r,x,y,v);
    sum[p]=sum[p<<1]+sum[p<<1|1];
}
ll Ask(int p,int l,int r,int x,int y)
{
    if(x>r||y=r)
    {
        return sum[p];
    }
    if(Lazy[p]) pushdown(p,l,r);
    int mid=(l+r)>>1;
    return Ask(p<<1,l,mid,x,y)+Ask(p<<1|1,mid+1,r,x,y);
}
int main()
{
    int k,l,r,x;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    biuldtree(1,1,n);
    while(q--)
    {
        scanf("%d%d%d",&k,&l,&r);
        if(k==1)
        {
            scanf("%d",&x);
            change(1,1,n,l,r,x);
        }
        else
        {
            printf("%lld\n",Ask(1,1,n,l,r));
        }
    }
    return 0;
}

5.并查集 O(近似常数)
luogu3367

#include
#include
#include
#include
#include
#include
using namespace std;
int father[200001];
int find(int x)
{
    if(father[x]==x) return x;
    return father[x]=find(father[x]);
}
void hebing(int x,int y)
{
    father[y]=x;
}
int main()
{
    int n,m,i,z,x,y,z1,z2;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++) father[i]=i;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&z,&x,&y);
        if(z==1)
        {
            z1=find(x);
            z2=find(y);
            if(z1!=z2)
            {
                hebing(z1,z2);
            }
        }
        else
        {
            if(find(x)==find(y)) printf("Y\n");
            else printf("N\n");
        }
    }
    return 0;
}

6.迪杰斯特拉(边不能有负权) O(mlogn)
NKOJ3639

#include//这个在比赛中不加,这道题不加好像要被卡
#include
#include
#include
#define ll long long
using namespace std;
struct Node
{
	int Num;
	ll dis;
	bool operator<(const Node &a) const
	{
		return a.dis q;
int n,m;
ll dis[400010],Len[2000010];
int End[2000010],Next[2000010],Last[400010];
bool mark[400010];
void Dij(int s)
{
	int v,u;
	Node temp;
	temp.Num=s;
	temp.dis=0;
	q.push(temp);
	while(!q.empty())
	{
		u=q.top().Num;
		q.pop();
		if(mark[u]) continue;
		mark[u]=1;
		for(int i=Last[u];i;i=Next[i])
		{
			v=End[i];
			if(!mark[v]&&dis[v]>dis[u]+Len[i])	
			{
				dis[v]=dis[u]+Len[i];
				temp.Num=v,temp.dis=dis[v];
				q.push(temp);
			}
		}
	}
}
int main()
{
	int x,y;
	ll z;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%lld",&x,&y,&z);
		End[i]=y;
		Len[i]=z;
		Next[i]=Last[x];
		Last[x]=i;
	}
	scanf("%d%d",&x,&y);
	memset(dis,0x3f,sizeof(dis));
	dis[x]=0;
	Dij(x);
	printf("%lld",dis[y]);
	return 0;
}

7.Floyd(不能有负权回路) O(n^3)
hdoj1599

#include
using namespace std;
int n,m;
int dis[101][101];
int Map[101][101];
int ans;
void floyd()
{
	int i,j,k;
	for(k=1;k<=n;k++)
	{
		for(i=1;i

8.spfa
时间复杂度O(kE)
k指每个点的平均进队次数,一般为2
E指边的总数,所以期望时间复杂度为O(2E)
可用于负权
可判断负权回路:每个点的进队次数不超过N
信息学奥赛一本通1382

#include
#include
#include
using namespace std;
const int N=500010<<1;
queue q;
int n,m;
int End[N],Last[N],Next[N],Len[N];
int dis[N];
bool mark[N];
//int cnt[N];
void spfa()
{
	int u,v; 
	mark[1]=1;
	q.push(1);
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		mark[u]=0;
		for(int i=Last[u];i;i=Next[i])
		{
			v=End[i];
			if(dis[v]>dis[u]+Len[i])
			{
				dis[v]=dis[u]+Len[i];
				if(!mark[v])
				{
					mark[v]=1;
					q.push(v);
					/*cnt[v]++;
					if(cnt[v]==n)
					{
						cout<<"有负环";
						exit(0);
					}*/
				}
			}
		}
	}
}
int main()
{
	int a,b,c;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		End[i]=b;
		Len[i]=c;
		Next[i]=Last[a];
		Last[a]=i;
		End[i+m]=a;
		Len[i+m]=c;
		Next[i+m]=Last[b];
		Last[b]=i+m;
	}
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	//cnt[1]=1;
	spfa();
	printf("%d",dis[n]);
	return 0;
}

9.克鲁斯卡尔 O(mlogm)
luogu3366

#include
#include
using namespace std;
int n,m;
int father[5010];
int ans,cnt;
struct Node
{
	int a,b,Len;
}Edge[200010];
inline bool cmp(Node a,Node b)
{
	return a.Len

10.prim O(n^2)
luogu3366

#include
#include
#include
using namespace std;
int n,m;
int Map[5010][5010];
int dis[5010];
int path[5010];
int ans;
void prim(int x)
{
	for(int i=1;i<=n;i++)
	{
		dis[i]=Map[i][x];
		path[i]=x;
	}
	int Min,flag;
	for(int i=1;idis[j])
			{
				Min=dis[j];
				flag=j;
			}
		}
		dis[flag]=0;
		for(int j=1;j<=n;j++)
		{
			if(dis[j]>Map[j][flag])
			{
				dis[j]=Map[j][flag];
				path[j]=flag;
			}
		}
	}
	for(int i=1;i<=n;i++)
	if(path[i]!=i) ans+=Map[i][path[i]];
	printf("%d",ans);
}
int main()
{
	int x,y,z;
	scanf("%d%d",&n,&m);
	memset(Map,0x3f,sizeof(Map));
	for(int i=1;i<=n;i++) Map[i][i]=0;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		Map[x][y]=Map[y][x]=min(Map[x][y],z);
	}
	prim(1);
	return 0;
}

11.Tarjan求有向图强连通分量
(1).在树上从根结点出发做一次DFS,记录每个结点的dfn值和后代的数量。设u有K个后代(不包括u自己)。如果满足:dfn[u] < dfn[v] <= dfn[u] + K 则表明u是v(v不是u)的祖先
信息学奥赛一本通1383

#include
#include
#include
using namespace std;
vector G[210];
stack s;
int ans,n,m,visitime,dfn[210],low[210],scc,Belong[210];
bool Instack[210],flag[210];
inline int _min(int a,int b)
{
	if(a

12.最长公共子串
设f[i][j]表示以A串第i个字符和B串第j个字符结尾的最长公共子串(答案:f数组中最大的一个)

if(A[i]==B[j]) f[i][j]=f[i-1][j-1]+1;
else f[i][j]=0;

13.最长公共子序列
设f[i][j]表示A串前i个字符和B串前j个字符结尾的最长公共子序列(答案:f[A.length][B.length])

if(A[i]==B[j]) f[i][j]=f[i-1][j-1]+1;
else f[i][j]=max(f[i-1][j],f[i][j-1]);

14.01矩阵矩阵:在01矩阵中找出一个最大全1正方形
设f[i][j]表示把点(i,j)作为一个正方形对角线(左上往右下)的右下角端点,能够得到的最大正方形的边长

if(a[i][j]==0) f[i][j]=0;
else f[i][j]=min(f[i-1][j-1],f[i-1][j],f[i][j-1])+1;

15.最大子矩阵:在带权(权值可正可负)矩阵中找出一个权值总和最大的矩阵
信息学奥赛一本通1282

#include
#include
#include
#include
#include
#include
using namespace std;
int sum[101][101],f[101][101][101];
int main()
{
    int n,m,i,j,t,k,ans=-0x7fffffff;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            scanf("%d",&t);
            sum[i][j]=t+sum[i-1][j];
        }
    }
    for(i=1;i<=n;i++)
    {
        for(j=i;j<=n;j++)
        {
            for(k=1;k<=n;k++)
            {
                t=sum[j][k]-sum[i-1][k];
                if(f[i][j][k-1]>0) f[i][j][k]=t+f[i][j][k-1];
                else f[i][j][k]=t;
                if(ans

16.01背包(倒序循环)
(1).使剩余空间最小
f[i]表示背包的剩余体积是否可以为i(f[0]=1,其余为0)

if(f[i-v[j]]) f[i]=1;

(2).使价值最大(不要求用完容积)
f[i]表示容积为i的背包能装下的最大价值(初始化全为0)

f[i]=max(f[i],f[i-v[j]]+value[j])

(3).使价值最大(要求用完容积)
f[i]表示容积为i的背包能装下的最大价值(初始化f[0]=0,其余为负无穷)

f[i]=max(f[i],f[i-v[j]]+value[j])

17.完全背包(正序循环)
(1).使剩余空间最小
f[i]表示背包的剩余体积是否可以为i(f[0]=1,其余为0)

if(f[i-v[j]]) f[i]=1;

(2).使价值最大(不要求用完容积)
f[i]表示容积为i的背包能装下的最大价值

f[i]=max(f[i],f[i-v[j]]+value[j]);

(3).使价值最大(要求用完容积)
参考01背包

18.二维背包
f[i][j]表示第一个背包容积为i,第二个背包容积为j时可获得的最大价值

f[i][j]=max(f[i][j],f[i-v[k]][j]+value[k],f[i][j-v[k]]+value[k]);

19.多重背包
信息学奥赛一本通1269

#include 
#include
using namespace std;
int v[10001],w[10001],s,f[6001];
int main()  
{  
    int n,m,i,a,b,c,j,k;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        for(j=1;j<=c;j<<=1)
        {
            s++;
            v[s]=j*a;
            w[s]=j*b;
            c-=j;
        }
        if(c==0) continue;
        s++;
        v[s]=a*c;
        w[s]=b*c;
    }
    for(i=1;i<=s;i++)
    {
        for(j=m;j>=v[i];j--)
        {
            f[j]=max(f[j],f[j-v[i]]+w[i]);
        }
    }
    printf("%d",f[m]);
    return 0;  
}   

20.混合背包(如果多重背包要二进制优化则会占用太多空间,时间复杂度只能稍优)
信息学奥赛一本通1270

#include  
#include  
using namespace std;
int w[31],c[31],p[31],f[201];
int main()  
{  
    int n,m,i,j,k,temp;
    scanf("%d%d",&m,&n);
    for(i=1;i<=n;i++)
    scanf("%d%d%d",&w[i],&c[i],&p[i]);
    for(i=1;i<=n;i++)
    {
        if(p[i]==0)
        for(j=w[i];j<=m;j++)
        f[j]=max(f[j],f[j-w[i]]+c[i]);
        else
        for(int j=1;j<=p[i];j++)
        for(int k=m;k>=w[i];k--)
        f[k]=max(f[k],f[k-w[i]]+c[i]);
    }
    printf("%d",f[m]);
    return 0;  
}

21.分组背包
信息学奥赛一本通1272

#include  
#include 
#include
using namespace std;
int w[31],c[31],p,f[201];
vector G[15];
int main()  
{  
    int n,v,t,i,j,k;
    scanf("%d%d%d",&v,&n,&t);
    for(i=1;i<=n;i++)
    scanf("%d%d%d",&w[i],&c[i],&p),G[p].push_back(i);
    for(i=1;i<=t;i++)//注意循环阶段
    for(j=v;j>=0;j--)
    for(k=0;k=0) f[j]=max(f[j],f[j-w[G[i][k]]]+c[G[i][k]]);
    printf("%d",f[v]);
    return 0;  
}

22.扩展欧几里得
(1).输入a,b,求ax+by=gcd(a,b)中的一组整数解

#include
using namespace std;
int a,b,x,y;
int E_gcd(int a,int b,int &x1,int &y1)
{
	if(b==0)
	{
		x1=1,y1=0;
		return a;
	}
	int x2,y2,d=E_gcd(b,a%b,x2,y2);
	x1=y2;
	y1=x2-a/b*y2;
}
int main()
{
	scanf("%d%d",&a,&b);
	int d=E_gcd(a,b,x,y);
	printf("%d %d",x,y);
	return 0;
} 

(2).ax+by=c是否有整数解
如果 c%gcd(a,b)==0则有解,否则无解
(3).ax+by=c的通解
设用扩欧求出ax1+by1=gcd(a,b)=d的一组解x1,y1,则(k为常数):
x=x1×c/d+k×b/d
y=y1×c/d-k×a/d
最小正整数解:若gcd(a, b) = d,则方程ax ≡ c (mod b)在[0, b/d - 1]上有唯一解
(4).解模线性方程组:ax≡1(mod b)表示ax%b=1%b
则:ax-by=1 用扩欧处理即可 注意判断是否有解
(5).解模线性方程组:ax≡b (mod n)
即:ax-ny=b 用扩欧处理
(6).解乘法逆元:ax≡1(mod n)的解x称为a在模n意义下的乘法逆元
则:ax-ny=1 所以gcd(a,n)==1才有逆元
注意:通过扩欧算出的解x必须要mod n,即(x+n)%n才是乘法逆元

int check(int a,int n)
{
	int x,y;
	if(kuoou(a,n,x,y)==1) return (x+n)%n;
	return -1;
}

(7).求(a/b) mod p
解:设b1是b在模p意义下的乘法逆元
则(a/b) mod p == (a×b1) mod p == ((a mod p)×(b1 mod p)) mod p

23.质数
(1).费马小定理:如果p是质数且gcd(a,p)==1,则ap-1%p == 1
所以ap-2就是a关于p的逆元
(2).对于一个正整数x,小于x且与x互质的正整数的个数叫做欧拉函数,记做φ(x)(φ(1)==1)

求解:φ(x)
公式1:φ(x)==x*(1-1/p1) * (1-1/p2)… * (1-1/pk)
其中:p1,p2…pk为x的所有质因数
NKOJ3550

#include
#include
#include
#include
#include
#define ll long long
using namespace std;
ll ans;
void phi(ll d)
{
    ans=d;
    ll i,a=d;
    for(i=2;i*i<=a;i++)
    {
        if(a%i==0)
        {
            ans-=ans/i;
            while(a%i==0)
            {
                a/=i;
            }
        }
    }
    if(a>1) ans-=ans/a;
}
int main()
{
    ll n;
    scanf("%lld",&n);
    phi(n);
    printf("%lld",ans);
    return 0;
}

公式2:如果x == pk,则φ(x) == (p-1) * (pk-1)(p为质数)

性质1:若gcd(x,y) == 1,则φ(x*y) == φ(x) * φ(y)
性质2:若x为质数,则φ(x) == x-1

线性筛求欧拉函数

void getphi(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(mark[i]==0) prime[++tot]=i,phi[i]=i-1;
        else//找一个模板题测一下这个else是否要
        {
            for(int j=1;j<=tot&&i*prime[j]<=n;j++)
            {
                mark[i*prime[j]]=1;
                if(i%prime[j]==0)
                {
                    phi[i*prime[j]]=prime[j]*phi[i];
                    break;
                }
                else
                {
                    phi[i*prime[j]]=phi[i]*(prime[j]-1);
                }
            }
        }
    }
}

(3).欧拉定理:若gcd(a,n) == 1,则aφ(n)%n == 1
应用1:若gcd(a,n) == 1,则 ab%n == ab%φ(n)%n (当b很大且n是质数的时候很好用)
应用2:若b>=φ(n),则ab %n== ab%φ(n)+φ(n)%n
(4).中国剩余定理:
(5).排列:从n个不同的元素中,取m个不重复的元素,按次序排列,称为从n个中取m个的排列。
Amn=n!/(n-m)!
(6).组合:从n个不同的元素中,取m个不重复的元素,不考虑次序,称为从n个中取m个的组合
Cmn=n!/(n-m)!/m!

性质1:Cmn=Cn-mn
性质2:C0n+C1n+C2n…+Cnn=2n
性质3:Cmn=Cmn-1+Cm-1n-1

long long C[1000][1000];
for(int i=1;i<=n;i++)C[i][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
C[i][j] = (C[i-1][j]+C[i-1][j-1]) % k;

卢卡斯定理:计算Cmn%p(p是质数)

ll C(ll a,ll b)
{
    if(aa-b) b=a-b;
    ll A=1,B=1;
    for(ll i=0;i

(7).二项式定理:(x+y)n=C0n * xn * y0+C1n * xn-1 * y1+…Cnn * x0 * yn

(8).第二类斯特林数:第二类斯特林数S2[n][m]表示把n个元素划分成m个非空集合的方案数。
S2[n][m] = S2[n-1][m-1] + m * S2[n-1][m]

void getStirling()
{
for(i=1;i<=n;i++)s2[i][1]=1;
for(int i=1;i<=n;i++)
for(int j=2;j<=i&&j<=m;j++)
s2[i][j]=(s2[i-1][j-1]+j*s2[i-1][j])%mod;
}

(9).第一类斯特林数:第一类斯特林数S1[n][m]表示把n个元素划分成m个非空循环排列集合的方案数。
S1[n][m] = S1[n-1][m-1] + (n-1) * S1[n-1][m]

void Stirling1(int n,int m){
S1[1][1]=1;
for(int i=2;i<=n;i++)
    for(int j=1;j<=i && j<=m;j++)
        S1[i][j]=S[i-1][j-1]+(i-1)*S[i-1][j];}

(10).bell数:BELL数B[n]表示把n个元素划分成若干个非空集合的方案数。
B[n] = S2[n][1]+S2[n][2]+S2[n][3]+ … +S2[n][n]
(11).判断质数之miller_rabin
输入多组数据,每组数据有n个正整数,判断有多少个质数

#include
#define ll long long
using namespace std;
ll n,a,ans;
ll quickpow(ll A,ll b,ll c)
{
	ll Ans=1;
	while(b)
	{
		if(b&1) Ans=(Ans*A)%c;
		A=(A*A)%c;
		b>>=1;
	}
	return Ans;
}
bool Miller_Rabin(ll k)
{
	ll d,r=0,x,y,z;
	if(k==2) return 1;
	if((k&1)==0||k<2) return 0;
	d=k-1;
	while((d&1)==0)
	{
		r++;
		d/=2;
	}
	for(int i=1;i<=10;i++)
	{
		z=rand()%(k-2)+2;
		x=quickpow(z,d,k);
		for(ll j=1;j<=r;j++)
		{
			y=(x%k*(x%k))%k;
			if(y==1&&x!=1&&x!=k-1) return 0;
			x=y;
		}
		if(x!=1) return 0;
	}
	return 1;
}
int main()
{
	while(scanf("%lld",&n)==1)
	{
		ans=0;
		for(ll i=1;i<=n;i++)
		{
			scanf("%lld",&a);
			if(Miller_Rabin(a)) ans++;
		}
		printf("%lld\n",ans);
	}
    return 0;   
}  

24.归并排序

#include 
#include 
#include 
#include 
#include
using namespace std;
int a[500010],b[500010];
long long ans;
int n;
void my_sort2(int l,int mid,int r)
{
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r)
    {
        if(a[i]<=a[j])
        {
            b[k]=a[i];
            k++;
            i++;
        }
        else
        {
            b[k]=a[j];
            k++;
            ans+=(long long)mid-i+1;
            j++;
        }
    }
    while(i<=mid) 
    {
        b[k]=a[i];
        k++;
        i++;
    }
    while(j<=r) 
    {
        b[k]=a[j];
        k++;
        j++;
    }
    for(i=l;i<=r;i++) a[i]=b[i];
}
void my_sort1(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    my_sort1(l,mid);
    my_sort1(mid+1,r);
    my_sort2(l,mid,r);
}
int main() 
{ 
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    my_sort1(1,n);
    printf("%lld",ans);
    return 0; 
}

25.快速幂

#include
#define ll long long
using namespace std;
ll A,B,C;
ll quickpow(ll a,ll b,ll c)
{
    ll ans=1;
    for(;b;b>>=1)
    {
        if(b&1) ans=ans*a%c;
        a=a*a%c;
    }
    return ans;
}
int main()
{
	scanf("%lld%lld%lld",&A,&B,&C);
	ll ans=quickpow(A,B,C);
	printf("%lld",ans);
    return 0;
}

26.枚举子集(s1是s的子集)

for(int s1=s;s1;s1=(s1-1)&s)
{
	//do something
}

27.高精度
(1).加

#include
#include
#include
#include
#include
using namespace std;
string s,y;
string jiafa(string x,string y)
{
	int i,l1=x.length(),l2=y.length(),a[201],b[201],c[202],flag=0,x1=0;
	string s1="";
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	for(i=0;i=1;i--)
	{
		s1+=char(c[i]+48);
	}
	return s1;
}
int main()
{
	cin>>s>>y;
	string s1=jiafa(s,y);
	cout<

(2).减

#include
#include
#include
#include
using namespace std;
void jianfa(char x[201],char y[201])
{
	int i,lx=strlen(x),ly=strlen(y),a[201],b[201],c[201],c1=0;
	char z[201];
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	if(lx==ly&&strcmp(x,y)==-1||lx1) i--;
	for(;i>=1;i--)
	printf("%d",c[i]);
}
int main()
{
	char a[201],b[201];
	scanf("%s%s",&a,&b);
	jianfa(a,b);
	return 0;
}

(3).乘

#include
#include
#include
#include
using namespace std;
void jiafa(char x[201],char y[201])
{
	int i,a[201],b[201],c[202],x1=0,lx=strlen(x),ly=strlen(y),j;
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	for(i=0;i1) i--;
	for(;i>=1;i--)
	printf("%d",c[i]);
}
int main()
{
	char x[201],y[201];
	scanf("%s%s",&x,&y);
	jiafa(x,y);
	return 0;
}

你可能感兴趣的:(复习)