9.29noip模拟试题
环上的游戏(cycle)
有一个取数的游戏。初始时,给出一个环,环上的每条边上都有一个非负整数。这些整数中至少有一个0。然后,将一枚硬币放在环上的一个节点上。两个玩家就是以这个放硬币的节点为起点开始这个游戏,两人轮流取数,取数的规则如下:
(1)选择硬币左边或者右边的一条边,并且边上的数非0;
(2)将这条边上的数减至任意一个非负整数(至少要有所减小);
(3)将硬币移至边的另一端。
如果轮到一个玩家走,这时硬币左右两边的边上的数值都是0,那么这个玩家就输了。
如下图,描述的是Alice和Bob两人的对弈过程,其中黑色节点表示硬币所在节点。结果图(d)中,轮到Bob走时,硬币两边的边上都是0,所以Alcie获胜。
现在,你的任务就是根据给出的环、边上的数值以及起点(硬币所在位置),判断先走方是否有必胜的策略。
【输入格式】
第一行一个整数N(N≤20),表示环上的节点数。
第二行N个数,数值不超过30,依次表示N条边上的数值。硬币的起始位置在第一条边与最后一条边之间的节点上。
【输出格式】
仅一行。若存在必胜策略,则输出“YES”,否则输出“NO”。
【样例】
cycle.in cycle.out
4
2 5 3 0 YES
cycle.in cycle.out
3
0 0 0 NO
最后取到数的人获胜
博弈
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 比较简单的博弈题 手动模拟一下 */ #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,a[50],s; int main() { freopen("cycle.in","r",stdin); freopen("cycle.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) if(a[i]==0)break; else s++; for(int i=n;i>=1;i--) if(a[i]==0)break; else s++; if(s&1)printf("YES\n"); else printf("NO\n"); return 0; }
舞蹈课(dancingLessons)
问题描述
有n个人参加一个舞蹈课。每个人的舞蹈技术由整数来决定。在舞蹈课的开始,他们从左到右站成一排。当这一排中至少有一对相邻的异性时,舞蹈技术相差最小的那一对会出列并开始跳舞。如果相差最小的不止一对,那么最左边的那一对出列。一对异性出列之后,队伍中的空白按原顺序补上(即:若队伍为ABCD,那么BC出列之后队伍变为AD)。舞蹈技术相差最小即是的绝对值最小。
你的任务是,模拟以上过程,确定跳舞的配对及顺序。
输入
第一行为正整数:队伍中的人数。下一行包含n个字符B或者G,B代表男,G代表女。下一行为n个整数。所有信息按照从左到右的顺序给出。在50%的数据中,。
输出
第一行:出列的总对数k。接下来输出k行,每行是两个整数。按跳舞顺序输出,两个整数代表这一对舞伴的编号(按输入顺序从左往右1至n编号)。请先输出较小的整数,再输出较大的整数。
样例输入
4
BGBG
4 2 4 3
样例输出
2
3 4
1 2
样例输入
4
BGBB
1 1 2 3
样例输出
1
1 2
贪心
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 贪心+堆优化 一开始把所有挨着的男女放进去 然后拿出Abs最小的 同时看看新生成的挨着的能不能组合成一组 注意一些细节的处理 开始wa了一个点 */ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> #define maxn 200010 #define inf 0x7fffffff using namespace std; int n,a[maxn],cnt,f[maxn],s1,s2; char c[maxn]; struct node{ int l,r,C; bool operator < (const node &x) const{ if(x.C==C)return x.l<l; return x.C<C; } }ans[maxn],t; priority_queue<node>q; int init(){ int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } int Abs(int x){ return x<0?-x:x; } int main() { // freopen("dancingLessons.in","r",stdin); //freopen("dancingLessons.out","w",stdout); n=init(); scanf("%s",c+1); for(int i=1;i<=n;i++) if(c[i]=='B')s1++; else s2++; for(int i=1;i<=n;i++) a[i]=init(); for(int i=2;i<=n;i++) if(c[i-1]!=c[i]) q.push((node){i-1,i,Abs(a[i]-a[i-1])}); while(!q.empty()){ int falg=0; while(1){ if(q.empty()){falg=1;break;} t=q.top();q.pop(); if(f[t.l]||f[t.r])continue; else break; } if(q.empty()&&falg)break;//这里多一个falg标记 表示q空时最后一个合不合法 ans[++cnt].l=t.l;ans[cnt].r=t.r; f[t.l]=1;f[t.r]=1; int L=t.l-1,R=t.r+1; while(f[L])L--; while(f[R])R++; if(L&&R<=n&&c[L]!=c[R]) q.push((node){L,R,Abs(a[R]-a[L])}); } printf("%d\n",cnt); for(int i=1;i<=cnt;i++) printf("%d %d\n",ans[i].l,ans[i].r); return 0; }
数位和乘积(digit.cpp/c/pas)
【题目描述】
一个数字的数位和乘积为其各位数字的乘积。求所有的N位数中有多少个数的数位和乘积恰好为K。请注意,这里的N位数是可以有前导零的。比如01,02视为二位数,但是他们的数位和乘积都是0。
【输入格式】
一行两个整数N,K
【输出格式】
一个行一个整数表示结果。
【样例输入】
2 3
【样例输出】
2
【样例输入2】
2 0
【样例输出2】
19
【数据范围】
对于20%:N <= 6。
对于50%:N<=16
存在另外30%:K=0。
对于100%:N <= 50,0 <= K <= 10^9。
暴力50
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 我是蒟蒻没有想出正解... 打了个暴力 当然也不是裸裸的 k==0 10^n-9^n 分成两段 每段分别暴力 在hash一下(不知为啥hash最小的数据不对 写了map) 还有一些小剪枝 目测n<=15的都能过 但是说好的%30<=16结果全尼玛是16 你故意的吧 然后就只拿到了基础的暴力分50 */ #include<iostream> #include<cstdio> #include<cstring> #include<map> #include<ctime> #define mod 233333 using namespace std; int n,k,N,falg,ans[100],J[100]; map<int,int>p; void Add(int a[100],int b[100]){ int c[30]; memset(c,0,sizeof(c)); int len=max(a[0],b[0]); for(int i=1;i<=len;i++) c[i]=a[i]+b[i]; for(int i=1;i<=len;i++) if(c[i]>9){ c[i+1]++;c[i]%=10; } if(c[len+1])len++;c[0]=len; for(int i=0;i<=len;i++)a[i]=c[i]; } void Jian(int a[100],int b[100]){ int c[100]; memset(c,0,sizeof(c)); int len=max(a[0],b[0]); for(int i=1;i<=len;i++) c[i]=a[i]-b[i]; for(int i=1;i<=len;i++) if(c[i]<0){ c[i+1]--;c[i]+=10; } for(int i=len;i>=0;i--) if(c[i]){ c[0]=i;break; } for(int i=0;i<=len;i++)a[i]=c[i]; } void Mul(int a[100],int x){ int c[100]; memset(c,0,sizeof(c)); int len=a[0]; for(int i=1;i<=len;i++) c[i]=a[i]*x; for(int i=1;i<=len;i++) if(c[i]>9){ c[i+1]+=c[i]/10; c[i]%=10; } while(c[len+1]>9){ len++; c[len+1]+=c[len]/10; c[len]%=10; } if(c[len+1])len++;c[0]=len; for(int i=0;i<=len;i++)a[i]=c[i]; } void Cal(int x){ int a[100]; memset(a,0,sizeof(a)); while(x){ a[++a[0]]=x%10;x/=10; } Add(ans,a); } void Dfs(int now,int s,int r){ if(r>k)return; if(now==N+1){ if(!falg)p[r]++; else{ if(r){ int t=k/r; if(t*r==k)Cal(p[t]); } } return; } for(int i=1;i<=9;i++) Dfs(now+1,s*10+i,r*i); } void Solve(){ ans[0]=1;ans[1]=1; J[0]=1;J[1]=1; for(int i=1;i<=n;i++) Mul(ans,10); for(int i=1;i<=n;i++) Mul(J,9); Jian(ans,J); } int main() { //freopen("digit.in","r",stdin); //freopen("digit.out","w",stdout); scanf("%d%d",&n,&k); if(k==0)Solve(); else{ N=n/2;Dfs(1,0,1); falg=1; N=n;Dfs(n/2+1,0,1); } for(int i=max(ans[0],1);i>=1;i--) printf("%d",ans[i]); return 0; }
正解dp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 正解还是很机智的Orz f[i][j][k][l][r]前i位选了j个2 k个3 l个5 r个7的方案数 然后+个高精就ok了 */ #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,k,ans[100],J[100]; int f[32][32][32][32][40]; void Add(int a[100],int b[100]){ int c[30]; memset(c,0,sizeof(c)); int len=max(a[0],b[0]); for(int i=1;i<=len;i++) c[i]=a[i]+b[i]; for(int i=1;i<=len;i++) if(c[i]>9){ c[i+1]++;c[i]%=10; } if(c[len+1])len++;c[0]=len; for(int i=0;i<=len;i++)a[i]=c[i]; } void Jian(int a[100],int b[100]){ int c[100]; memset(c,0,sizeof(c)); int len=max(a[0],b[0]); for(int i=1;i<=len;i++) c[i]=a[i]-b[i]; for(int i=1;i<=len;i++) if(c[i]<0){ c[i+1]--;c[i]+=10; } for(int i=len;i>=0;i--) if(c[i]){ c[0]=i;break; } for(int i=0;i<=len;i++)a[i]=c[i]; } void Mul(int a[100],int x){ int c[100]; memset(c,0,sizeof(c)); int len=a[0]; for(int i=1;i<=len;i++) c[i]=a[i]*x; for(int i=1;i<=len;i++) if(c[i]>9){ c[i+1]+=c[i]/10; c[i]%=10; } while(c[len+1]>9){ len++; c[len+1]+=c[len]/10; c[len]%=10; } if(c[len+1])len++;c[0]=len; for(int i=0;i<=len;i++)a[i]=c[i]; } void Cal(int x){ int a[100]; memset(a,0,sizeof(a)); while(x){ a[++a[0]]=x%10;x/=10; } Add(ans,a); } void Solve(){ ans[0]=1;ans[1]=1; J[0]=1;J[1]=1; for(int i=1;i<=n;i++) Mul(ans,10); for(int i=1;i<=n;i++) Mul(J,9); Jian(ans,J); for(int i=max(ans[0],1);i>=1;i--) printf("%d",ans[i]); } void solve(){ int t1=0,t2=0,t3=0,t4=0; while(k%2==0)k/=2,t1++; while(k%3==0)k/=3,t2++; while(k%5==0)k/=5,t3++; while(k%7==0)k/=7,t4++; if(k>1){cout<<0;return;} f[0][0][0][0][0]=1; f[0][0][0][0][1]=1; for(int i=1;i<=n;i++) for(int j=t1;j>=0;j--) for(int k=t2;k>=0;k--) for(int l=t3;l>=0;l--) for(int r=t4;r>=0;r--){ if(j>=1)Add(f[j][k][l][r],f[j-1][k][l][r]);//2 if(k>=1)Add(f[j][k][l][r],f[j][k-1][l][r]);//3 if(j>=2)Add(f[j][k][l][r],f[j-2][k][l][r]);//4 if(l>=1)Add(f[j][k][l][r],f[j][k][l-1][r]);//5 if(j>=1&&k>=1)Add(f[j][k][l][r],f[j-1][k-1][l][r]);//6 if(r>=1)Add(f[j][k][l][r],f[j][k][l][r-1]);//7 if(j>=3)Add(f[j][k][l][r],f[j-3][k][l][r]);//8 if(k>=2)Add(f[j][k][l][r],f[j][k-2][l][r]);//9 } for(int i=max(f[t1][t2][t3][t4][0],1);i>=1;i--) printf("%d",f[t1][t2][t3][t4][i]); } int main() { //freopen("digit.in","r",stdin); //freopen("digit.out","w",stdout); scanf("%d%d",&n,&k); if(k==0)Solve(); else solve(); return 0; }