1. 超级麻将 【题意描述】 所谓超级麻将没有了砣、索、万的区分,每种牌上的数字可以是 1~100,而每种数字的牌各有 100 张。另外特别自由的是,玩牌的人手里想拿多少张牌都可以,好刺激哦! 刺激归刺激,但是拿多了怎么胡牌呢? 超级麻将规定只要一个人手里拿的牌是若干句话(三个连续数字的牌各一张组成一句话,三张或者四张同样数字的牌也算一句话),再加上一对相同的牌,就算胡了。 【样例输入】 3 2 4 0 0 0 0 0 …… 0(一共 98 个 0) 2 4 2 0 0 0 0 …… 0(一共 97 个 0) 2 3 2 0 0 0 0 …… 0(一共 97 个 0) 【样例输出】 Yes Yes No 本题DP,f[i][j][k]表示当前在第i号位置,且在第i号取了一对对子,其中1- (i-2) 号位置已经取完,第i-1号位置取了j个,第i-2号位置取了k个。g[i][j][k]的含义同上,只是在第i号位置没有取对子。 状态转移方程见代码。#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=110; bool f[maxn][maxn][maxn],g[maxn][maxn][maxn]; int a[maxn]; int main(){ int T; scanf("%d",&T); while(T--){ memset(f,false,sizeof(f)); memset(g,false,sizeof(f)); For(i,1,100) scanf("%d",&a[i]); g[0][0][0]=true; For(i,1,100) For(j,0,a[i-1]) For(k,0,a[i]){ if(k>=2) f[i][j][k]|=g[i][j][k-2]; if(k>=3) f[i][j][k]|=f[i][j][k-3]; if(k>=4) f[i][j][k]|=f[i][j][k-4]; if(a[i-2]>=k && j>=k) f[i][j][k]|=f[i-1][a[i-2]-k][j-k]; if(k>=3) g[i][j][k]|=g[i][j][k-3]; if(k>=4) g[i][j][k]|=g[i][j][k-4]; if(a[i-2]>=k && j>=k) g[i][j][k]|=g[i-1][a[i-2]-k][j-k]; } printf("%s\n",f[100][a[99]][a[100]]?"Yes":"No"); } return 0; }
2
二分图
【题意描述】一个无向图被称为二分图当且仅当这个图中没有长度为奇数的环。给你一个包含 n 个点的图,这个图中一开始没有边。要求支持两种操作:在这个图中加入一条边。删除最后加入的边。每个操作之后需要判断这个图是否是二分图,如果是输出“ YES”,否则输出“ NO”
【输入格式】第一行包含两个整数 n 和 m,表示点数和询问数。接下来 m 行每行包含一个询问,格式如下:
1 x y(表示加入一条连接 x 和 y 的边)
2(表示删除最后加入的边)
【输出格式】输出共 m 行,每行包含一个字符串“ YES”或者一个字符串“ NO”
【样例输入】
3 3
1 1 2
1 2 3
1 3 1
【样例输出】
YES
YES
NO
【数据规模与约定】对于 80%的数据, n<=100,m<=3000。对于额外 15%的数据,没有第二种操作。对于 100%的数据,n<=10000,m<=1000000。
本题的做法是伪并查集,即在find()时不要路径压缩,具体细节见代码。#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int maxn=10010; int n,m; int cnt; int fa[maxn],st[maxn*100][2],front[maxn],vis[maxn]; int find(int x){ if(x==fa[x]) return x; else return find(fa[x]); } void link(int x,int y){ x=find(x);y=find(y); if(x==y){ st[++cnt][0]=-1; return; } fa[x]=y; st[++cnt][0]=x; st[cnt][1]=y; } void pop(){ if(st[cnt][0]==-1){ cnt--; return; } int x=st[cnt][0]; int y=st[cnt][1]; fa[x]=x; cnt--; } bool together(int x,int y){ return find(x)==find(y); } int main(){ scanf("%d%d",&n,&m); int i,j,k; for(i=1;i<=n*2;i++) fa[i]=i; int last=0; for(int kase=1;kase<=m;kase++){ int op; scanf("%d",&op); if(op==1){ int x,y; scanf("%d%d",&x,&y); front[kase]=last; if(vis[last]==1) vis[kase]=1; else if(together(x+n,y+n) || together(x,y)) vis[kase]=1; else{ link(x,y+n); link(x+n,y); } last=kase; if(vis[last]) printf("NO\n"); else printf("YES\n"); }else{ if(vis[last]==0){ pop();pop(); } last=front[last]; if(vis[last]) printf("NO\n"); else printf("YES\n"); } } return 0; }
3.
【问题描述】
数学题。
函数求值:
【输入格式】第一行一个整数 T,表示有 T 个询问。接下来 T 行,每行第一个数 n。
【输出格式】
T 行,每行表示第 i 个询问中 F(n)的值
【样例输入 1】
5 1 2 3 4 5
【样例输出 1】
1 3 7
11
21
解决本题基于三个定理:
①当a为质数时 f(a)=a*(a-1)+1;
②当a为质数时 f(a^2)=f(a)*a*a-a+1,更高次方推理类似
③当gcd(a,b)==1时 f(a*b)=f(a)*f(b)#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define For(i,j,k) for(int i=j;i<=(k);i++) using namespace std; const int maxn=10001000; typedef long long LL; int zhishu[maxn]; int s[maxn]; LL f[maxn]; void getzhishu(){ For(i,2,maxn-1) zhishu[i]=1; For(i,2,maxn-1){ if(zhishu[i]){ for(int j=i<<1;j<maxn;j+=i) zhishu[j]=0; } } } void solve(){ for(LL i=1;i<maxn;i++) f[i]=1LL; for(LL i=2;i<maxn-1000;i++){ if(zhishu[i]){ s[i]=i; f[i]=(LL)(i-1)*i+1; for(LL j=i,k=j*i;j<maxn && k<maxn;j=k,k=j*i){ f[k]=(f[j]*i*i)-i+1; s[k]=i; } } if(s[i]){ for(LL j=2;j*i<maxn;j++){ if(j%s[i]){ f[j*i]=f[i]*f[j]; } } } } } int main(){ getzhishu(); solve(); LL T,n; scanf("%lld",&T); while(T--){ scanf("%lld",&n); printf("%lld\n",f[n]); } return 0; }
Keep on coding 8-26
最新推荐文章于 2024-04-05 14:25:09 发布