常见算法模板

快速幂

//求a^k的前三位和后三位
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll fast_power(ll base,ll power,ll mod){
	ll result=1;
	while(power>0){
		if(power&1)
			result=result*base%mod;	
		power>>=1;
		base=(base*base)%mod;
	}
	return result;
}
int main(){
	int t,v=1;
	scanf("%d",&t);
	while(t--){
		ll n,k,x;
		double ka,y,xy,j;
		scanf("%lld %lld",&n,&k);
		ka=k*log10(1.0*n);
		x=(int)ka;
		y=ka-x;
		xy=pow(10,y)*100;
		printf("Case %d: %d %03lld\n",v++,(int)xy,fast_power(n,k,1000));
	//后三位用0补 
	}
	return 0;
}
//求前三位:
//
//每一个数n都可以写作10^t(t大多是小数),则此时n^k可写作10^kt 
//n=10^a 
//n^k=10^ka 
//ka=x+y(x是整数部分,y是小数部分)
//n^k=10^x * 10^y
//因为x是整数,所示10^x是1,10,100,1000…表示的是n^k有多少位, 
//y是小数,10^y表示的是n^k的具体的数值。
//所以我们要求n^k的前a位,即求10^(a-1+y)
//(为什么是a-1? 答:指数函数10^x,当x>0时,10^x>1)
//https://blog.csdn.net/qq_43746332/article/details/96750087

快读

inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;
        c = getchar();
    }

    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}

马拉车

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
char s[210010],str[210010];
int len[210010];//i位置最长回文串的半径 
int main()
{
	while(~scanf("%s",str))
	{
		int i,j,k=2,l;
		s[0]='$';
		s[1]='#';
		l=strlen(str);
		for(i=0;i<l;i++)
		{
			s[k++]=str[i];
			s[k++]='#';
		}
		int id,mx=0,ans=0;
		for(i=1;i<k;i++)
		{
			len[i]=i<mx ? min(mx-i,len[2*id-i]) : 1;
		
/*当 mx - i > P[j] 的时候,以 S[j] 为中心的回文子串包含在
以 S[id]为中心的回文子串中,由于 i 和 j 对称,
以 S[i] 为中心的回文子串必然包含在
以 S[id]为中心的回文子串中,
所以必有 P[i] = P[j],其中 j = 2id - i
			*/
			
			while(s[i+len[i]]==s[i-len[i]])
				len[i]++;
				
			if(i+len[i]>mx)
			{
				mx=i+len[i];
				id=i;
			}
			ans=max(ans,len[i]-1);//最长子串的长度是半径减1,		
		}
		printf("%d\n",ans);
	}
	return 0;
}

最小生成树

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAX=1e3+10,INF=0x7fffffff;
char s[MAX*3][10];
int e[MAX*2][MAX*2],dis[MAX*2],book[MAX*2];
int n;
void init()
{
	memset(e,0,sizeof(e));
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i==j)
			e[i][j]=0;
			else
			e[i][j]=INF;
		}
	}
}
void solve()
{
	while(~scanf("%d",&n)&&n)
	{
		int i,j,k;
		memset(s,0,sizeof(s));
		memset(dis,0,sizeof(dis));
		memset(book,0,sizeof(book));
		getchar();		
		init();
		for(i=1;i<=n;i++)
			gets(s[i]);
		
		int num=0;
		for(i=1;i<n;i++)
		{
			for(j=i+1;j<=n;j++)
			{
				int sum=0;
				for(k=0;k<7;k++)
				{
					if(s[i][k]!=s[j][k])
					{
						sum++;
					}
				}
				e[j][i]=e[i][j]=sum;			
			}			
		}
		
		for(i=1;i<=n;i++)
			dis[i]=e[1][i];
		
		book[1]=1;
		
		int count=1,minn,s=0;
		while(count<n)
		{
			minn=INF;
			for(i=1;i<=n;i++)
			{
				if(book[i]==0&&dis[i]<minn)
				{
					minn=dis[i];
					j=i;
				}				
			}
			book[j]=1;
			count++;
			s+=dis[j];
			for(int k=1;k<=n;k++)
			{
				if(book[k]==0&&dis[k]>e[j][k])
				dis[k]=e[j][k];
			}
		}
		printf("The highest possible quality is 1/%d.\n",s);
	}
} 
int main()
{
	solve();
	return 0;
}

最短路

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=0x7fffffff,MAX=1e3+10;
int e[MAX][MAX],book[MAX],vis[MAX],s[MAX];
int T,S,D,r,n,minn,x,y,k,a;
void dij() {
	memset(book,0,sizeof(book));
	for(int i=0; i<=n; i++)
		vis[i]=e[0][i];
	book[0]=1;
	for(int i=0; i<n; i++) {
		minn=INF;
		for(int j=0; j<=n; j++) {
			if(vis[j]<minn&&!book[j]) {
				k=j;
				minn=vis[j];
			}
		}
		book[k]=1;
		for(int j=0; j<=n; j++)
			if(vis[j]>vis[k]+e[k][j]&&!book[j])
				vis[j]=vis[k]+e[k][j];
	}

}
void init() {
	memset(e,0x3f,sizeof(e));
	for(int i=0; i<MAX; i++) {
		e[i][i]=0;
	}
}
void solve() {
	while(scanf("%d%d%d",&T,&S,&D)!=EOF) {
		n=0;
		init();
		for(int i=1; i<=T; i++) {
			scanf("%d%d%d",&x,&y,&r);
			n=max(max(n,x),y);
			if(e[x][y]>r)
				e[x][y]=e[y][x]=r;
		}
		minn=INF;
		for(int i=0; i<S; i++) {
			scanf("%d",&a);
			e[0][a]=e[a][0]=0;
		}
		for(int i=0; i<D; i++)
			scanf("%d",&s[i]);

		dij();
		for(int i=0; i<D; i++)
			minn=min(minn,vis[s[i]]);
		printf("%d\n",minn);
	}
}
int main() {
	solve();
	return 0;
}

字典树

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e6+10;
int tot=1,n;
int ch[maxn][30],po[maxn];
void insert(char *s){
	int l=strlen(s),u=0;
	for(int i=0;i<l;i++){
		int v=s[i]-'a';
		if(!ch[u][v])
			ch[u][v]=++tot;
		u=ch[u][v];
		po[u]++;
	}
}
bool search(char *s){
	int l=strlen(s),u=0;
	for(int i=0;i<l;i++){
		int v=s[i]-'a';
		if(!ch[u][v])
			return false;
		u=ch[u][v];
	}
	return po[u];//删除删的是po数组,而ch[u][v]还存在 
}
void dele(char *s){
	int l=strlen(s),u=0;
	for(int i=0;i<l;i++){
		int v=s[i]-'a';
		if(!ch[u][v])
			return ;
		u=ch[u][v];
	}
	int e=po[u];
	u=0;
	for(int i=0;i<l;i++){
		int v=s[i]-'a';
		u=ch[u][v];
		po[u]-=e;
	}
	for(int i=0;i<26;i++)
		ch[u][i]=0;
}
void solve(){
	scanf("%d",&n);
	memset(ch,0,sizeof(ch));
	memset(po,0,sizeof(po));
	while(n--){
		char s[40],a[40];
		scanf("%s %s",s,a);
		switch (s[0]){
			case 'i':insert(a);break;
			case 's':
				if(search(a))
					printf("Yes\n");
				else
					printf("No\n");
				break;
			default :dele(a);break;
		}
	}
}
int main(){
	solve();
	return 0;
}

优先队列

priority_queue <int,vector,greater > q;//升序队列
priority_queue <int,vector,less >q;//降序队列
//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)

/* 					______________              ______________               ________________                          
				  /  ____________|            /  ____________ \             |  ____________  \                   
		         /  /                        / /             \ \            | |            \  \          
				/  /                        / /               \ \           | |             \  \     
			   /  /        _________       / /                 \ \          | |              \  \ 
			   \  \       |___  ___/       \ \                 / /          | |              /  /
				\  \          \ \           \ \               / /           | |             /  /
				 \  \__________\ \           \ \_____________/ /            | |____________/  /  
God	Bless		  \_______________\           \_______________/             |________________/                          
*/
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
priority_queue<ll,vector<ll>,greater<ll> > q;//按升序排列 0 1 2 3
int main()
{
	ll i,j,n,k,x;
	scanf("%lld",&n);
	ll num=0,sum=0;
	for(i=1;i<=n;i++)
	{
		scanf("%lld",&x);
		if(x>=0)//如果是正值肯定要喝 
		{
			sum+=x;
			num++;
			q.push(x); 
		}
		else 
		{
			if((sum+x)>=0)//如果是负值但喝了没死先喝再说 
			{
				sum+=x;
				num++;
				q.push(x); 
			}
			else
			{
	/*如果是负值这瓶喝完就死,
	找到(优先队列顶端(greater从小到大排序)就是最小)
	之前喝的比这个还'毒'的,喝这个不喝之前那个 */
				if(!q.empty() &&x>q.top() )				
				{
					sum-=q.top() ;
					q.pop() ;
					q.push(x);
					sum+=x;
				}
			}
		}
	} 
	printf("%lld\n",num);
	return 0;
}

中国剩余定理

#include <stdio.h>
#include <string.h>
struct xa
{
	int prim;
	int mod;
}a[1000];
int main()
{
	int n,m,flag,i,j,v;
	memset(a,0,sizeof(a));
	scanf("%d",&n);
	
	for(j=1;j<=n;j++)
		scanf("%d %d",&a[j].prim ,&a[j].mod  );
	
	int ans=a[1].mod ,s=1;
	for(i=1;i<n;i++)
	{
		s*=a[i].prim ;//质数的最小公倍数就是他们的乘积 
		while(ans%a[i+1].prim !=a[i+1].mod  )
		{
			ans+=s;
		}
	}
	printf("%d\n",ans);
	return 0;
}

线段树

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
ll sum[maxn*4],ma[maxn*4],num[maxn];
void build(int l,int r,int root){
	if(l==r){
		sum[root]=ma[root]=num[l];return;
	}
	int m=l+r>>1;
	build(l,m,root<<1);
	build(m+1,r,root<<1|1);
	sum[root]=sum[root<<1]+sum[root<<1|1];
	ma[root]=max(sum[root<<1],sum[root<<1|1]);
}
void update(int ul,int ur,int l,int r,int root){
	if(ma[root]==1||ma[root]==0) 
		return;
	if(l==r){
		ma[root]=sum[root]=sqrt(sum[root]);
		return;
	}
	int m=l+r>>1;
	if(ul<=m) 
		update(ul,ur,l,m,root<<1);
	if(m<ur) 
		update(ul,ur,m+1,r,root<<1|1);
	sum[root]=sum[root<<1]+sum[root<<1|1];
	ma[root]=max(ma[root<<1],ma[root<<1|1]);
}
ll query(int ql,int qr,int l,int r,int root){
	if(ql<=l&&r<=qr) 
		return sum[root];
	int m=l+r>>1;
	ll ans=0;
	if(ql<=m) 
		ans+=query(ql,qr,l,m,root<<1);
	if(m<qr) 
		ans+=query(ql,qr,m+1,r,root<<1|1);
	return ans;
}
int main()
{
    ll n,m;
	scanf("%lld",&n);
    for( int i=1; i<=n; i++ ) 
	scanf("%lld",&num[i]);
    build(1,n,1);
    scanf("%lld",&m);
    for( int i=0; i<m; i++ ){
    	ll op,a,b;
		scanf("%lld %lld %lld",&op,&a,&b);
    	if(op==1) 
			printf("%lld\n",query(a,b,1,n,1));
    	else 
			update(a,b,1,n,1);
	}
	return 0;
}

唯一分解定理

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
int a[10000000];
long long prim[10000000],num=1;
void getprim()//素数打表 
{
    for(int i=2;i<=10000000;i++)
    {
    	if(a[i]==0)
    	{
    		prim[num++]=i;
			for(int j=i;j<=10000000;j+=i)
    		{
    			a[j]=1;
			}
		}
	}
}
long long only(long long n)//唯一分解定理公式模板
{
    long long cnt,divisor=1;
    for(int i=1;i<num&&prim[i]*prim[i]<=n;i++)
    {
        if(n%prim[i]==0)
        {
            cnt=0;
            while(n%prim[i]==0)
            {
                cnt++;
                n/=prim[i];
            }
            divisor*=(cnt+1);        
        }
    }
    if(n > 1)
    	divisor*=2;
    //大于1就乘2,因为打表只能打到1e6,数据给的到了1e12
	//所以在大于1e6时还会有另一半因子
	//比如1e3对应的1e9
    return divisor;
}
int main()
{
	getprim();
	int t,v=1;
	scanf("%d",&t);
	while(t--)
	{
		long long n,m;
		scanf("%lld%lld",&n,&m);
		printf("Case %d: ",v++);
		if(n/m<m)
		{
		    printf("0\n");
            continue;
		}
		long long ans=only(n)/2;
		for(int i=1;i<m;i++)
		{
			if(n%i==0)//除掉小于最小边长m的错误数据 
				ans--; 
		}
		printf("%lld\n",ans);
	}
	return 0;
}

网络流之最大流

#include <iostream>
#include <queue>
#include<string.h>
using namespace std;
#define arraysize 201
int maxData = 0x7fffffff;
int capacity[arraysize][arraysize]; //记录残留网络的容量
int flow[arraysize];                //标记从源点到当前节点实际还剩多少流量可用
int pre[arraysize];                 //标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中
int n,m;
queue<int> myqueue;
int BFS(int src,int des) {
	int i,j;
	while(!myqueue.empty())       //队列清空
		myqueue.pop();
	for(i=1; i<m+1; ++i) {
		pre[i]=-1;
	}
	pre[src]=0;
	flow[src]= maxData;
	myqueue.push(src);
	while(!myqueue.empty()) {
		int index = myqueue.front();
		myqueue.pop();
		if(index == des)            //找到了增广路径
			break;
		for(i=1; i<m+1; ++i) {
			if(i!=src && capacity[index][i]>0 && pre[i]==-1) {
				pre[i] = index; //记录前驱
				flow[i] = min(capacity[index][i],flow[index]);   //关键:迭代的找到增量
				myqueue.push(i);
			}
		}
	}
	if(pre[des]==-1)      //残留图中不再存在增广路径
		return -1;
	else
		return flow[des];
}
int maxFlow(int src,int des) {
	int increasement= 0;
	int sumflow = 0;
	while((increasement=BFS(src,des))!=-1) {
		int k = des;          //利用前驱寻找路径
		while(k!=src) {
			int last = pre[k];
			capacity[last][k] -= increasement; //改变正向边的容量
			capacity[k][last] += increasement; //改变反向边的容量
			k = last;
		}
		sumflow += increasement;
	}
	return sumflow;
}
int main() {
	int i,j;
	int start,end,ci;
	while(cin>>n>>m) {
		memset(capacity,0,sizeof(capacity));
		memset(flow,0,sizeof(flow));
		for(i=0; i<n; ++i) {
			cin>>start>>end>>ci;
			if(start == end)               //考虑起点终点相同的情况
				continue;
			capacity[start][end] +=ci;     //此处注意可能出现多条同一起点终点的情况
		}
		cout<<maxFlow(1,m)<<endl;
	}
	return 0;
}

完全背包

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int num,cost,dp[110000],w[110000];
int main()
{
	int k,n,m,i,v,s,p;
	while(~scanf("%d %d",&k,&n))
	{
		v=1;
		memset(dp,0,sizeof(dp));
		//完全背包的二进制优化 
		for(i=1;i<=n;i++)
		{
			scanf("%d %d",&num,&cost );
			s=1;
			while(s<=num)
			{
				w[v++]=cost*s;
				num-=s;
				s=s*2;
			}
			if(num)
				w[v++]=cost*num;
		}
		for(i=1;i<v;i++)			
			for(int j=k;j>=w[i];j--)		
				dp[j]=max(dp[j],dp[j-w[i]]+w[i]);	
		
		printf("%d\n",dp[k]);
	}
	return 0;
} 

贪心

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int x[1001];
int main()
{
    int r,n,sum;
    while(scanf("%d%d",&r,&n)&&(r!=-1||n!=-1))
    {
    	int i,j,k;
	    for(i=0;i<n;i++)
	        scanf("%d",&x[i]); 
	    sort(x,x+n);
	    
	    i=0,sum=0;
	    while(i<n)
	    {
	        j=x[i++];
	        while(i<n&&x[i]<=j+r) 
				i++;
	        k=x[i-1];
	        while(i<n&&x[i]<=k+r) 
				i++;
	        sum++;
	    }
	    printf("%d\n",sum);
    }
    return 0;
}

拓扑排序

#include <stdio.h>
#include <string.h>
int book[301][301];
int s[300];
int vis[300];
int main()
{
	int n,m,t;
	scanf("%d",&t);
	while(t--)
    {
		int x,y,j,flag=0;
		scanf("%d %d",&n,&m);     
        memset(book,0,sizeof(book));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<m;i++)
        {
            scanf("%d %d",&y,&x);//坑一,题目给的后者比前者重; 
            if(book[x][y]==0)
            {
                book[x][y]=1;
                vis[y]++;
            }
        }
        int num=n,t,i;
		for(i=1;i<=n;i++)
		{
			for(j=n;j>=1;j--)//输出为字典序最小,因此从最大开始遍历 
		    {
		    	if(vis[j]==0)
		        {
		        	s[j]=num--;//记录j号球的重量num【从大到小排序】 
		            vis[j]--;
					t=j;
					break;
		        }
			}
			if(j==0)
			{
				flag=1;
				break;
			}
			for(int k=1;k<=n;k++)
		    {
		        if(book[t][k])
		            vis[k]-- ;
		    }
		}
		if(flag)
		{
			printf("-1\n");
			continue;
		}
        for(int i=1;i<=n;i++)
        {
        	if(i!=n)       	
        		printf("%d ",s[i]);
			else
				printf("%d\n",s[i]);
		}
    }
    return 0; 
}
/*
2

5 4
5 1
4 2
1 3
2 3

10 5
4 1
8 1
7 8
4 1
2 8
							   重量:1 2 3 4 5 (1) 
ans:				**从轻到重 顺序:5 1 4 2 3 (2) 
					**输出每个测试用例输出单行从标签1到标签N的球的权重
					**(2)中从1到5对应(1)的权值 :即:2 4 5 3 1		 
2 4 5 3 1        

5 1 6 2 7 8 3 4 9 10
*/ 

约瑟夫环

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int k,n,m,ans;
int main() {
	while(~scanf("%d %d %d",&n,&k,&m)&&(n||m||k)) {
		ans=0;
		for(int j=2; j<n; j++)
			ans=(ans+k)%j;
		ans=(ans+m)%n;
		printf("%d\n",ans+1);
	}
	return 0;
}

欧拉函数

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ll;
const int MAX=1e6+10;
ll a[MAX],n;
void init()
{
	a[1]=0;
	for(int i=2;i<=MAX;i++)
		a[i]=i;
	for(int i=2;i<=MAX;i++)
		if(a[i]==i)		
		for(int j=i;j<=MAX;j+=i)			
			a[j]=a[j]/i*(i-1);
	for(int i=2;i<=MAX;i++)
	a[i]=a[i]+a[i-1];
}
void solve() {
	init();
	while(~scanf("%llu",&n)&&n)
		printf("%llu\n",a[n]);	
}
int main() {
	solve();
	return 0;
}

树状数组

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,k,l,r;
int a[100010],b[100010];
int lowbit(int x){
	return x&(-x);
}
void add1(int x,int y){
	while(x<=n){
		a[x]+=y;
		x+=lowbit(x);
	}
}
void add2(int x,int y){
	while(x<=n){
		b[x]+=y;
		x+=lowbit(x);
	}
}
int sum1(int x){
	int ans=0;
	while(x>0){
		ans+=a[x];
		x-=lowbit(x);
	}
	return ans;
}
int sum2(int x){
	int ans=0;
	while(x>0){
		ans+=b[x];
		x-=lowbit(x);
	}
	return ans;
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d %d %d",&k,&l,&r);
		if(k==1){
			add1(l,1);
			add2(r,1);
		}
		else
			printf("%d\n",sum1(r)-sum2(l-1));
	}
	return 0;
}

三分

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
double H,D,h;
double check(double x)//我们走到的点的位置 
{
	double l1=(D-x);
	double l2=H-(H-h)*D/x;
	return l1+l2;
}
int main()
{
	int t; scanf("%d",&t);
	while(t--)
	{
		scanf("%lf%lf%lf",&H,&h,&D);
		double l=(H-h)*D/H,r=D;//l,r表示的是人走的距离 
		//注意l要从(H-h)*D/H开始,不然墙上没有影子
		//人走的最大距离自然就是D 
		while(r-l>=1e-6)
		{
			double mid1=l+(r-l)/3.0,mid2=r-(r-l)/3.0;//三分不解释 
			if(check(mid1)>check(mid2)) r=mid2;//求最小不解释 
			else l=mid1;
		}
		printf("%.3lf\n",check(r));
		//check(l)和check(r)都可以,没理解?
		//大概是因为无限接近,并且直接的差小于10的-6次方
		//所以保留三位不影响结果 
	}
	return 0;
}

区间查质数

/* 					______________              ______________               ________________                          
				  /  ____________|            /  ____________ \             |  ____________  \                   
		         /  /                        / /             \ \            | |            \  \          
				/  /                        / /               \ \           | |             \  \     
			   /  /        _________       / /                 \ \          | |              \  \ 
			   \  \       |___  ___/       \ \                 / /          | |              /  /
				\  \          \ \           \ \               / /           | |             /  /
				 \  \__________\ \           \ \_____________/ /            | |____________/  /  
God	Bless		  \_______________\           \_______________/             |________________/                          
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const long long  MAX_L = 2e6+10;
const long long  MAX_SQRT_B = 2e6+10;
bool is_prime[MAX_L];
bool is_prime_small[MAX_SQRT_B];

void segment_sieve(ll a,ll b){
	for(int i=0;(ll)i*i<b;i++)
		is_prime_small[i] = true;
	// a= 4   b= 7	
//		is_prime_small[0]=1;
//		is_prime_small[1]=1;
//		is_prime_small[2]=1;
		
	for(int i=0;i<b-a;i++)
		is_prime[i] = true;
		//b-a=3;
//		is_prime[0]=0;
//		is_prime[1]=1;
//		is_prime[2]=0;
		
	for(int i=2;(ll)i*i<b;i++){
		if(is_prime_small[i]){
			for(int j=2*i;(ll)j*j<b;j+=i)
				is_prime_small[j] = false;
			for(ll j=max(2ll,(a+i-1)/i)*i;j<b;j+=i)
				is_prime[j-a] = false;
		}
	}
}
int main(){
	ll a,b,sum=0;
	scanf("%lld %lld",&a,&b);
	segment_sieve(a, b);
	for(int i=0;i<b-a;i++)
	if(is_prime[i])
	sum++;
	printf("%lld\n",sum);	
	return 0;
} 

强连通分量

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
const int MAX=1e3+10,inf=0x7fffffff;
vector<int> v[MAX];//存路
stack<int> s;//栈,用来储存和清除连接的点,若连通该强连通分量所有点都会出栈
int n,m,x,y,num,sum,cnt;
int dfn_clock;//每个时间戳的标号
int s_s[MAX];//记录当前点所在哪一个强连通分量内
int dfn[MAX];//时间戳
bool instack[MAX];//判断该点是否在栈内
int low[MAX];//记录所属强连通
int cost[MAX];//记录ACMer打电话到每个人的费用
int min_cost[MAX];//记录联系当前强连通分量中电话费最少的
int in[MAX];//入度
void tarjan(int x) {
	dfn[x]=low[x]=++dfn_clock;
	s.push(x);
	instack[x]=true;
	for(int i=0; i<v[x].size(); i++) {
		int u=v[x][i];
		if(!dfn[u]) {
			tarjan(u);
			low[x]=min(low[x],low[u]);
		} else if(instack[u])
			low[x]=min(low[x],dfn[u]);
	}
	if(dfn[x]==low[x]) {
		int u,minn=inf;
		cnt++;
		do {
			u=s.top();
			s.pop() ;
			instack[u]=false;
			s_s[u]=cnt;
			if(cost[u]<minn)
				minn=cost[u];
		} while(u!=x);
		min_cost[cnt]=minn;
	}
}
void find() {//如果是两个图中间或某一个点与其它点都不连通,也要算作一个强连通;
	dfn_clock=cnt=0;
	for(int i=1; i<=n; i++)
		if(!dfn[i])
			tarjan(i);
}
void init() {
	memset(min_cost,0,sizeof(min_cost));
	memset(s_s,0,sizeof(s_s));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(cost,0,sizeof(cost));
	memset(in,0,sizeof(in));
	for(int i=1;i<=n;i++)
	v[i].clear() ; 
}
void solve() {
	while(~scanf("%d %d",&n,&m)) {
		init();
		for(int i=1; i<=n; i++)
			scanf("%d",&cost[i]);

		for(int i=1; i<=m; i++) {
			scanf("%d %d",&x,&y);
			v[x].push_back(y);
		}
		find();

		for(int i=1; i<=n; i++) {
			for(int j=0; j<v[i].size() ; j++) {
				int u=v[i][j];
				if(s_s[i]!=s_s[u])
					in[s_s[u]]++;
			}
		}
		num=0,sum=0;
		for(int i=1; i<=cnt; i++)
			if(in[i]==0) {
				num++;
				sum+=min_cost[i];
			}
		printf("%d %d\n",num,sum);
	}
}
int main() {
	solve();
	return 0;
}

欧拉回路

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=1e6+10;
int head[maxn],nex[maxn],to[maxn];
bool flag[maxn];
int in[maxn],out[maxn];
int tot=1,t,n,m;
vector<int> v;
inline void add(int v,int u){
	to[++tot]=u;
	nex[tot]=head[v];
	head[v]=tot;
}
void dfs(int x){
	for(int &i=head[x],y;y=to[i],i;i=nex[i]){
		int c=(t==1?i/2:i-1);
		int sig=i%2;
		if(flag[c])
			continue;
		flag[c]=1;
		dfs(y);
		if(t==1)
			v.push_back(sig?-c:c);
		else
			v.push_back(c);
	}
}
int main(){
	scanf("%d %d %d",&t,&n,&m);
	for(int i=1;i<=m;i++){
		int v,u;
		scanf("%d %d",&v,&u);
		add(v,u);
		if(t==1)
			add(u,v); 
		out[v]++;
		in[u]++;
	}
	if(t==1){
		for(int i=1;i<=n;i++){
			if((in[i]+out[i])%2){
				printf("NO\n");
				return 0;
			}
		}
	}
	else
	{
		for(int i=1;i<=n;i++){
			if(in[i]!=out[i]){
				printf("NO\n");
				return 0;
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(head[i]){
			dfs(i);
			break;
		}
	}
	if(v.size()!=m){
		printf("NO\n");
		return 0;
	}
	printf("YES\n");
	for(int i=m-1;i>=0;i--)
		printf("%d ",v[i]);
	
	return 0;
}

记忆化优先搜索

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int mapp[200][200],dp[200][200],n,m;
int find(int x,int y)
{
	if(dp[x][y])
		return dp[x][y];
		
	int i,j,dx,dy;
	int k=mapp[x][y];
	for(i=0; i<=k; i++)
	{
		for(j=0; j<=k-i; j++)
		{
			dx=x+i;
			dy=y+j;
			if(i==0&&j==0)
			continue;
			if(dx<1||dy<1||dx>n||dy>m)
				continue;
			dp[x][y]=(find(dx,dy)+dp[x][y])%10000;
		}
	}
	return dp[x][y];
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int i,j;
		memset(dp,0,sizeof(dp));
		scanf("%d %d",&n,&m);
		for(i=1; i<=n; i++)
			for(j=1; j<=m; j++)
				scanf("%d",&mapp[i][j]);
		dp[n][m]=1;
		printf("%d\n",find(1,1));
	}
	return 0;
}

字符串哈希

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ULL;
const int maxn=1e6+10;
ULL power[maxn],hs[maxn],b=233333;
char s[maxn];
void solve()
{
	power[0]=1;
	for(int i=1;i<=maxn;i++)
		power[i]=power[i-1]*b;
		
	while(~scanf("%s",s+1))
	{
		if(s[1]=='.')
			break;
		int l=strlen(s+1);
		hs[0]=0;
		for(int i=1;i<=l;i++)
			hs[i]=hs[i-1]*b+(ULL)(s[i]-'a'+2333);
		
		
		int ans=1;
		for(int i=1;i<=l;i++)
		{
			if(l%i!=0)
				continue;
				
			ULL mm=hs[i]-hs[0]*power[i];
		//	printf("%ull****%d\n",mm,i);
			int j;
			
			for(j=i;j<=l-i;j+=i)
			{
			//	ULL nn=(ULL)(hs[j+i]-hs[j]*power[i]);
			//	printf("%ull@@@\n",nn);
				if(mm!=(ULL)(hs[j+i]-hs[j]*power[i]))
					break;
			}
				
		//	printf("%d****\n",j);
			if(j>=l)
			{
				ans=l/i;
				break;
			}			
		}
		printf("%d\n",ans);
	}
}
int main()
{
	solve();
	return 0;
}

哈希表

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod1=99999,mod2=999999,p1=233,p2=2333,maxn=3e4+10;
int tot=0,nxt[maxn],poi[mod1],endd[maxn];
void insert(int x,int y)
{
	nxt[++tot]=poi[x];
	poi[x]=tot;
	endd[tot]=y;
}
int query(int x,int y)
{
	for(int i=poi[x];i!=0;i=nxt[i])
		if(endd[i]==y)
			return 1;
	
	return 0;
}
void solve()
{
	int t;
	char op[12],s[205];
	scanf("%d",&t);
	while(t--)
	{
		scanf("%s",op);
		gets(s);
		int len=strlen(s),sum1=0,sum2=0;
		for(int i=0;i<len;i++)
		{
			sum1=(sum1*p1+s[i])%mod1;
			sum2=(sum2*p2+s[i])%mod2;
		}
		if(op[0]=='a')
			insert(sum1,sum2);
		else
		{
			if(query(sum1,sum2))
				printf("yes\n");
			else
				printf("no\n");
		}
	}
}
int main()
{
	solve();
	return 0;
}

割点

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,tot,root,rs,dfn_clock;
const int maxn=1e3+5;
int head[maxn],to[maxn],nex[maxn],cut[maxn];
int dfn[maxn],low[maxn];
inline void add(int v,int u){
	to[tot]=u;
	nex[tot]=head[v];
	head[v]=tot++;
}
void tarjan(int u,int f){
	low[u]=dfn[u]=++dfn_clock;
	for(int i=head[u];i!=-1;i=nex[i]){
		int v=to[i];
		if(!dfn[v]){
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				if(u!=root)
					cut[u]=1;
				else
					rs++;
			}
		}
		else if(v!=f)
			low[u]=min(low[u],dfn[v]);
	}
}
int main(){
	while(~scanf("%d",&n)&&n)
	{
		memset(head,-1,sizeof(head));
		memset(low,0,sizeof(low));
		memset(dfn,0,sizeof(dfn));
		memset(cut,0,sizeof(cut));
		tot=0;
		root=0;
		rs=0;
		dfn_clock=0;
		int x,y;
		while(~scanf("%d",&x)&&x){
			while(getchar()!='\n'){
				scanf("%d",&y);
				add(x,y);
				add(y,x);	
			}
		}
		for(int i=1;i<=n;i++){
			if(!dfn[i]){
				root=i;
				rs=0;
				tarjan(i,i);
				if(rs>=2)
					cut[i]=1;
			}
		}	
		int sum=0;
		for(int i=1;i<=n;i++){
			if(cut[i]==1)
			sum++;
		}
		printf("%d\n",sum);
	}
}

二分图最大匹配

#include <stdio.h>
#include <string.h>
int n,m,book[100],match[100],e[110][110];
int bfs(int u)
{
	int i;
	for(i=1;i<=n;i++)
	{
		if(book[i]==0 && e[u][i]==1)
		{
			book[i]=1;
			
			if(match[i]==0 || bfs(match[i]))
			{
				match[i]=u;
				match[u]=i;
				return 1;
			}
		}
			
	}
	return 0;
}
int main()
{
	int i,j,t1,t2,sum=0;
	scanf("%d %d",&n,&m);//n个点m条边 
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&t1,&t2);
		e[t1][t2]=1;
		e[t2][t1]=1;//无向图 
	}	
	
	memset(match,0,sizeof(match));
	
	for(i=1;i<=n;i++)
	{
		memset(book,0,sizeof(book));
		if(bfs(i))
		sum++;
	}
	
	printf("%d",sum);
	
	return 0;
}

多重背包

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
struct xa
{
	int cost;
	int weight;
	int number;
}a[1100];
int dp[300];
int main()
{
	int c;
	scanf("%d",&c);
	while(c--)
	{
		int n,m,i,j,k;
		memset(dp,0,sizeof(dp));
		scanf("%d %d",&n,&m);
		for(i=1;i<=m;i++)
			scanf("%d %d %d",&a[i].cost,&a[i].weight ,&a[i].number );
		for(i=1;i<=m;i++)
		for(k=1;k<=a[i].number ;k++)
		for(j=n;j>=a[i].cost ;j--)
			dp[j]=max(dp[j],dp[j-a[i].cost]+a[i].weight );
		printf("%d\n",dp[n]);
	}
	return 0;
}

01背包

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int p[105];
double f[105];
int n,t;
double ff;
double dp[100005];//抢到价值为i的钱逃走的最大概率
int sum;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		sum=0;
		scanf("%lf %d",&ff,&n);
		for(int i=0;i<n;i++)
		{
			scanf("%d %lf",&p[i],&f[i]);
			sum+=p[i];
		}
 
		memset(dp,0,sizeof(dp));
		dp[0]=1;
		for(int i=0;i<n;i++)//遍历所有能选项 
			for(int j=sum;j>=p[i];j--)//根据p[i]确定背包容量范围进行遍历 
				dp[j]=max(dp[j],dp[j-p[i]]*(1-f[i]));//选p[i]和不选p[i]求最大值 
				
        int m=0;
		for(int i=sum;i>=0;i--)//从容量最大开始遍历 
		{
			if(dp[i]>=1-ff)//找到能逃走的临界值 
			{
				m=i;
				break;
			}
		}		
		printf("%d\n",m);
	}
}

kmp

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
char s[1000000],t[1000000];
int nexx[1000000];
int n,T,num,lens,lent;
void getnexx()
{
	int j=0,k=-1;
	nexx[0]=-1;
	while(j<lent)
	{
		if(k==-1||t[k]==t[j])	
		{
			j++;
			k++;
			nexx[j]=k;	
		}
		else
			k=nexx[k];
	}
}
void kmp()
{
	int i=0,j=0;
	while(i<lens)
	{
		if(j==-1||s[i]==t[j])
		{
			i++;
			j++;
		}
		else
			j=nexx[j];
		if(j==lent)
		{
			num++;
			j=nexx[j];
		}
	}
}
void solve()
{
	scanf("%d",&T);
	while(T--){
		memset(s,0,sizeof(s));
		memset(t,0,sizeof(t));
		memset(nexx,0,sizeof(nexx));
		scanf("%s %s",t,s);
		lens=strlen(s);
		lent=strlen(t);
		num=0;
		getnexx();
		kmp();
		printf("%d\n",num);
	}
}
int main()
{
	solve();
	return 0;
 } 

RMQ

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+10,p=17;
int n,k,a[maxn],log[maxn],f[maxn][p+1],z[maxn][p+1];
int main(){
	scanf("%d %d",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	log[0]=-1;
	for(int i=1;i<=n;i++){
		f[i][0]=z[i][0]=a[i];
		log[i]=log[i>>1]+1;
	}
	for(int j=1;j<=p;j++){
		for(int i=1;i+(1<<j)-1<=n;i++){
			f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
			z[i][j]=min(z[i][j-1],z[i+(1<<j-1)][j-1]);
		}
	}
	n=n-k+1;
	int x,y,s;
	for(int i=1;i<=n;i++){
		x=i;
		y=i+k-1;
		s=log[y-x+1];
		printf("%d %d\n",max(f[x][s],f[y-(1<<s)+1][s]),min(z[x][s],z[y-(1<<s)+1][s]));
	}
	return 0;
}

倍增求LCA

#include <bits/stdc++.h>
using namespace std;
const int ONE=100010;
int n,Q,x,y;
int nexx[ONE*2],first[ONE*2],go[ONE*2],tot;
int Dep[ONE];
int f[ONE][22];
void Add(int u,int v){
	nexx[++tot]=first[u];
	first[u]=tot;
	go[tot]=v;
}
void Deal_first(int u,int father){
	Dep[u]=Dep[father]+1;
	for(int i=0;i<=19;i++){
		f[u][i+1]=f[f[u][i]][i];
	}
	for(int e=first[u];e;e=nexx[e]){
		int v=go[e];
		if(v==father)
			continue;
		f[v][0]=u;
		Deal_first(v,u);	
	}
}
int LCA(int x,int y){
	if(Dep[x]<Dep[y])
		swap(x,y);
	for(int i=20;i>=0;i--){
		if(Dep[f[x][i]]>=Dep[y])
			x=f[x][i];
		if(x==y)
			return x;
	}
	for(int i=20;i>=0;i--){
		if(f[x][i]!=f[y][i]){
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
int dist(int x,int y){
	return Dep[x]+Dep[y]-2*Dep[LCA(x,y)];
}
int main(){
	tot=0;
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		Add(x,y);
		Add(y,x);
	}
	Deal_first(1,0);
	scanf("%d",&Q);
	while(Q--){
		scanf("%d%d",&x,&y);
		printf("%d\n",dist(x,y));
	}
	return 0;
}

并查集

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char s[10];
int f[100000],ke[100000],book[100000];
int Case=1,a,b,all,n,m;
int getf(int v) {
	return f[v]==v?v:f[v]=getf(f[v]);
}
void merge(int v,int u) {
	int t1=getf(v);
	int t2=getf(u);
	if(t1!=t2)
		f[t2]=t1;
}
void init() {
	for(int i=0; i<n; i++)
		f[i]=i,ke[i]=i;
}
void solve() {
	while(~scanf("%d %d",&n,&m)&&(n||m)) {
		init();
		all=n;
		memset(book,0,sizeof(book));
		for(int i=1; i<=m; i++) {
			scanf("%s",s);
			if(s[0]=='M') {
				scanf("%d %d",&a,&b);
				merge(ke[a],ke[b]);
			} else {
				scanf("%d",&a); 
				f[all]=all;
				ke[a]=all;
				all++;
			}
		}
		int ans=0;
		for(int i=0;i<n;i++)
		{
			int t=getf(ke[i]);
			if(!book[t])
			{
				ans++;
				book[t]=1;
			}
		}		
		printf("Case #%d: %d\n",Case++,ans);
	}
}
int main() {
	solve();
	return 0;
}

尺取法

/* 					______________              ______________               ________________                          
				  /  ____________|            /  ____________ \             |  ____________  \                   
		         /  /                        / /             \ \            | |            \  \          
				/  /                        / /               \ \           | |             \  \     
			   /  /        _________       / /                 \ \          | |              \  \ 
			   \  \       |___  ___/       \ \                 / /          | |              /  /
				\  \          \ \           \ \               / /           | |             /  /
				 \  \__________\ \           \ \_____________/ /            | |____________/  /  
God	Bless		  \_______________\           \_______________/             |________________/                          
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int a[100010];
int main()
{
	int t,i,j;
	scanf("%d",&t);
	while(t--)
	{
		int n,s;
		memset(a,0,sizeof(a));
		scanf("%d %d",&n,&s);
		for(i=1;i<=n;i++)
			scanf("%d",&a[i]);
		
		int minn=n+1;
		int sum=0,end=1,top=1;
		/*top表示头部,end表示尾部
		尺取:将头部一直往前去,知道满足条件为止,然后将尾巴往前移动一位。
		将此时长度与minn比较,将更小的赋值给minn,循环这个操作,直到不能再满足条件了
		*/ 
		while(1)
		{
			while(top<=n&&sum<s)
			{
				sum+=a[top];
				top++;
			}
			if(sum<s)
				break;
				
			minn=min(minn,top-end);//top-end表示长度 
			sum-=a[end++];
		}
		if(minn<n+1)
			printf("%d\n",minn);
		else 			
			printf("0\n");
	}
	return 0;
} 

叉乘

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
struct point//记录点的坐标 
{
	double x,y;
};
struct line//记录线段的始端点和尾端点 
{
	point st,ed;
};
//判断两条线段是否相交:https://www.cnblogs.com/tuyang1129/p/9390376.html 
//叉乘:ab X ac 
double mul(point a,point b,point c)
{
	return (b.x -a.x )*(c.y -a.y )-(b.y -a.y )*(c.x -a.x ); 
}
bool find(line l1,line l2)
{
	//如果l1(或l2)两端点的横坐标最大值仍比l2(或l1)两端点的横坐标最小值小,那么一定不相交; 
	if(max(l1.st.x ,l1.ed.x )<min(l2.st.x ,l2.ed.x )||max(l2.st.x ,l2.ed.x )<min(l1.st.x ,l1.ed.x ))
		return false;
	//同理,纵坐标 
	if(max(l1.st.y ,l1.ed.y )<min(l2.st.y ,l2.ed.y )||max(l2.st.y ,l2.ed.y )<min(l1.st.y ,l1.ed.y ))
		return false;
	/*
	定理:向量a×向量b(×为向量叉乘),
	若结果小于0,表示向量b在向量a的顺时针方向;
	若结果大于0,表示向量b在向量a的逆时针方向;
	若等于0,表示向量a与向量b平行。
	
	如果线段CD的两个端点C和D,
	与另一条线段的一个端点(A或B,只能是其中一个)连成的向量,
	与向量AB做叉乘,
	若结果异号,表示C和D分别在直线AB的两边,
	若结果同号,则表示CD两点都在AB的一边,则肯定不相交。
	*/ 

	//叉乘,判断l2的两端点是否满足与l1相交的条件 
	if(mul(l1.st,l1.ed,l2.st)*mul(l1.st,l1.ed,l2.ed)>0)
		return false;
	//同理,判断l1的两端点是否满足与l2相交的条件 
	if(mul(l2.st,l2.ed,l1.st)*mul(l2.st,l2.ed,l1.ed)>0)
		return false;
	return true;
}
bool judge(point a,point b,point c,point d,line l1)
{
	line l2;
	//l2依次代表矩形四边,分别判断是否相交 
	l2.st =a;
	l2.ed =b;
	if(find(l1,l2))
		return true;
	
	l2.st =a;
	l2.ed =d;
	if(find(l1,l2))
		return true;
	
	l2.st =c;
	l2.ed =b;
	if(find(l1,l2))
		return true;
		
	l2.st =c;
	l2.ed =d;
	if(find(l1,l2))
		return true;
	return false;
}
void solve()
{
	int t;
	point a,b,c,d;
	line l;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%lf %lf %lf %lf %lf %lf %lf %lf",&l.st.x ,&l.st.y ,&l.ed.x ,&l.ed.y ,&a.x ,&a.y ,&c.x ,&c.y );
		//并非按照左上,右下输入,需判断 
		if(a.x >c.x )
			swap(a.x ,c.x );
		if(a.y <c.y )
			swap(a.y ,c.y );
		int flag=0;
		//逆时针记录矩形四点 
		b.x =a.x ,b.y =c.y ;
		d.x =c.x ,d.y =a.y ;
		//判断线段是否与矩形四条边相交 
		if(judge(a,b,c,d,l))
			flag=1;
		//特殊情况:判断线段是否有一端点在矩形内,若果有那么一定相交(可以理解为这是一个实心矩阵) 
		if((l.st.x >=a.x &&l.st.x <=c.x&&l.st.y>=c.y &&l.st.y<=a.y )||(l.ed.x >=a.x &&l.ed.x <=c.x&&l.ed.y>=c.y &&l.ed.y<=a.y ))
			flag=1;
		
		if(flag)
			printf("T\n");
		else
			printf("F\n");
	}
}
int main()
{
	solve();
	return 0;
}

差分约束系统

#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+10,inf=0x3f3f3f3f;
int a,b,d,n,ml,md,tot=0;
int head[maxn],nex[maxn],to[maxn],weight[maxn];
int dis[maxn],book[maxn],cnt[maxn];
void add(int v,int u,int k){
	nex[tot]=head[v];
	to[tot]=u;
	weight[tot]=k;
	head[v]=tot++;
}
bool spfa(int x){
	queue<int> q;
	memset(dis,inf,sizeof(dis));
	memset(book,0,sizeof(book));
	book[x]=1;
	dis[x]=0;
	q.push(x);
	cnt[x]++;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		book[u]=0;
		for(int i=head[u];i!=-1;i=nex[i]){
			int v=to[i];
			int w=weight[i];
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				if(!book[v]){
					cnt[v]++;
					book[v]=1;
					q.push(v);
					if(cnt[v]>n)
						return true;
				}
			}
		}
	}
	return false;
}
int main(){
	memset(head,-1,sizeof(head));
	memset(cnt,0,sizeof(cnt));
	scanf("%d %d %d",&n,&ml,&md);
	for(int i=1;i<=ml;i++){
		scanf("%d %d %d",&a,&b,&d);
		add(a,b,d);
	}
	for(int i=1;i<=md;i++){
		scanf("%d %d %d",&a,&b,&d);
		add(b,a,-d);
	}
	for(int i=1;i<=n;i++){
		add(0,i,0);	
	}
	if(spfa(0)){
		printf("-1\n");
		return 0;
	}
	spfa(1);
	if(dis[n]==inf)
		printf("-2\n");
	else
		printf("%d\n",dis[n]);
	return 0;
}

佐威夫博弈

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
double p=(sqrt(5.0)+1)/2.0;//差值*1.618==minn(两堆中较小那堆的数量)
//若相等为奇异局势,先手必败 
void solve()
{
	double n,m,c;
	while(~scanf("%lf %lf",&n,&m))
	{
		c=(n-m)>0?n-m:m-n;
		n=n<m?n:m;
		if(int(c*p)==int(n))
			printf("0\n");
		else
			printf("1\n");
	}
}
int main()
{
	solve();
	return 0;
 } 
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值