南京理工大学第八届程序设计大赛(校外镜像)题解报告
整体来说,这次的题目还是不错的,只是有几题居然是原题,着实有点让人心醉...
A.偷吃糖果
Time Limit: 1000Ms
Memory Limit: 65536KB
Description
他有两盒糖果,两盒糖果分别仅由小写字母组成的字符串s和字符串t构成。当中'a'到'z'表示详细的某种糖果类别。他原本打算送给他喜欢的女生,可是要送给女孩子的话两盒糖果不能有区别(即字符串s和t全然同样)。所以,他决定偷吃几块,他吃糖果的策略是每次选出一盒糖果中两个连续的同种类别的糖果,然后吃掉当中一块。该策略能够使用多次。
比如一盒糖果是'rrrjj',他能够把这盒糖果变成'rrjj'或者'rrrj'。如今你要告诉小鱼。经过他多次偷吃糖果之后。两盒糖果是否能送给他喜欢的女孩子。假设能够输出'Yes',假设不行输出'No'。
解题思路:此题思路还是简单的,由于题目明白吃糖果的策略为每次选出一盒糖果中两个连续的同种类别的糖果,然后吃掉当中一块,所以对于每一种糖果,仅仅要一開始有,那么终于必然至少会留下一块,那么为了便于处理,我们能够将两个字符串简化,同种类别糖果仅仅留下一块,以便于比較
比如第一组例子,rrrjj与rrrj,简化后的效果为rj与rj,非常明显符合
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<deque> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 using namespace std; const int N = 1000 + 10; const int M = 40; const int inf = 100000000; const int mod = 2009; char a[N],b[N]; int main() { int t,i,k; scanf("%d",&t); while(t--) { scanf("%s%s",a,b); k=0; a[k++]=a[0]; for(i=1;a[i]!='\0';i++) if(a[i]==a[i-1]) continue; else a[k++]=a[i]; a[k++]='\0'; //puts(a); k=0; b[k++]=b[0]; for(i=1;b[i]!='\0';i++) if(b[i]==b[i-1]) continue; else b[k++]=b[i]; b[k++]='\0'; //puts(b); if(strcmp(a,b)) puts("No"); else puts("Yes"); } return 0; }
解题思路:求[a,b]区间内与n互质的数的个数,我们能够转化为[1,b]内与n互质的数的个数减去[1,a-1]内与n互质的数的个数
而要求[1,b]内与n互质的数的个数,我们能够非常自然地想到容斥原理
求解区间[a,b]中与k互质的个数
首先对k进行质数分解,然后与这个因子GCD!=1则共同拥有n/ki个
有计算反复的部分,因此利用 容斥原理: k1+k2+k3-k1*k2-.....求出与k不互质的个数。用总的减去就可以
然后blabla,就是单纯的容斥原理模板题,话说此题就是一道原题,hdu4135
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<deque> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 #define ll long long using namespace std; const int N = 20 + 10; const int M = 10000 + 10; const int inf = 100000000; const int mod = 2009; int k,prime[N]; ll factor[M]; void get_prime(ll n) { k=0; for(ll i=2;i*i<=n;i++) if(n%i==0) { prime[k++]=i; while(n%i==0) n/=i; } if(n>1) prime[k++]=n; } ll Exclusion(ll n) { int i,j,p=0,q; ll sum=0; factor[p++]=-1; for(i=0;i<k;i++) { q=p; for(j=0;j<q;j++) factor[p++]=factor[j]*prime[i]*(-1); } for(i=1;i<p;i++) sum+=n/factor[i]; return sum; } int main() { int t; ll a,b,n; scanf("%d",&t); while(t--) { scanf("%lld%lld%lld",&a,&b,&n); get_prime(n); printf("%lld\n",b-Exclusion(b)-(a-1-Exclusion(a-1))); } return 0; }
解题思路:据说是莫比乌斯反演,只是本人并没有搞出来,看看日后会不会更它,主要看我懒不懒
此处临时放上一种AC的代码
#include<stdio.h> #include<math.h> #define LL long long #define MAXN 100010 LL C[MAXN]={0}; void Init(){ C[1]=C[2]=0; LL i,j; for(i=3;i<MAXN;i++) C[i]=i*(i-1)*(i-2)/6; } LL digui(int N){ if(N<3) return 0; if(N==3) return 1; int i; LL sum; for(i=2,sum=0;i<N;i++){ if(N/i>=3){ sum+=digui(N/i); } } return C[N]-sum; } int main(){ int T; int N,M; scanf("%d",&T); Init(); while(T--){ scanf("%d%d",&N,&M); if(N/M<3) printf("0\n"); else{ printf("%lld\n",digui(N/M)); } } return 0; }
解题思路:不得不说,这是第二道原题,有印象的同学必然会记得"最少拦截系统",只是hdu的数据就有点水了,不是正解
我的做法是用STL set来模拟,由于set会自己主动帮我们排序,而每次进来的数,要找比当前进来的数小的最大数进行更新,假设不存在则插入一个新的,终于set的大小size()就是题目要求的结果
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<deque> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 #define ll long long using namespace std; const int N = 20 + 10; const int M = 10000 + 10; const int inf = 100000000; const int mod = 2009; set<int> s; set<int>::iterator it1,it2; int main() { int t,x,n,i; scanf("%d",&t); while(t--) { s.clear(); scanf("%d",&n); scanf("%d",&x); s.insert(x); for(i=1;i<n;i++) { scanf("%d",&x); it2=s.upper_bound(x); it1=it2; it1--; if(it2==s.begin()) s.insert(x); else { s.erase(it1); s.insert(x); } } printf("%d\n",s.size()); } return 0; }
解题思路:首先,我们已经知道了B的最高位数字为n,那么我们就能够来模拟一下除法的过程
就拿例子来举例子
我们每一轮除法得到的商会作为下一轮的被除数,当然,不能忘了考虑上一轮由于除不尽留下的余数,就这样一直计算到被除数s[i]能被除数k整除且商为n的时候结束
除了n=0,k=0时,B=0
其它k=0的时候,B=-1(无解)
由上述方法算出的结果还让我错了一次
比如n=1,k=2时,B=105263157894736842,那么A=052631578947368421,非常显然,这样是不正确的,移动前的A不可能含有前导0,所以我们还要推断当B的位数>=2时,从高到低来看,第二位不能为0,否则也是无解的情况
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<deque> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 #define ll long long using namespace std; const int N = 10000 + 10; const int M = 10000 + 10; const int inf = 100000000; const int mod = 2009; int ans[N],s[N]; int main() { int t,n,k,p,i,c; scanf("%d",&t); while(t--) { i=p=c=0; scanf("%d%d",&n,&k); if(!n&&!k) { puts("0"); continue; } if(!k) { puts("-1"); continue; } s[i]=n; while(!((s[i]+c)%k==0&&(s[i]+c)/k==n)) { ans[p]=(s[i]+c)/k; c=((s[i]+c)%k)*10; i++; s[i]=ans[p]; p++; } if(s[1]==0&&p>=2) { puts("-1"); continue; } for(i=0;i<=p;i++) printf("%d",s[i]); puts(""); } return 0; }
H.谁才是最强战舰!
Time Limit: 1000MS
Memory Limit: 65536KB
Description
于是,提督君想了一个简单的游戏,来分出她们的胜负。
游戏规则例如以下:这里有N堆石子,每堆石子有a[i](1<=i<=N)个。每人轮流从当中的某一堆石子中拿出随意个石子(仅仅能在当中一堆拿。不能不拿),大和先手。谁拿出了最后一个石子,谁输。若大和必胜,输出“Yamato_Saikou!”,若依阿华必胜,输出“Meidikeji_Shijiediyi!”。若两边都无法必胜。输出“Sayonara_Konosekai!”.
解题思路:非常显然,这是一道博弈题,并且是尼姆博弈的变型,谁拿完谁输,本人还是用了模板,有兴趣学习一下尼姆博弈的能够点此链接->尼姆博弈
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<deque> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 using namespace std; const int N = 100000 + 10; const int M = 40; const int inf = 100000000; const int mod = 2009; long long h[N],w[N]; int main() { int t,x,ans,n,i,c; int num1,num2; scanf("%d",&t); while(t--) { scanf("%d",&n); ans=num1=num2=0; for(int i=0;i<n;i++) { scanf("%d",&x); if(x==1) num1++; //孤单堆 else num2++; //充裕堆 ans^=x; } if((ans&&num2!=0)||(!ans&&num2==0)) //S1,S2,T0必胜 puts("Yamato_Saikou!"); else //S0,T2必败 puts("Meidikeji_Shijiediyi!"); } return 0; }
J.water1
Time Limit: 1000MS
Memory Limit: 65536KB
Description
为了简化问题。如果水流下来的速度是每秒一个单位的水。而且总是往区域一降水(某沿海地区)。
如今请问要淹没全部的区域至少要多少时间(秒)?淹没的定义是,全部的区域表面至少覆盖一层水。如果没有区域则至少要放一滴水。上图样例中,淹没完例如以下:
解题思路:题目告诉我们'+'的高度和宽度,要我们填'w',最顶层须要一层的'w',问须要多少个'w'
题目明白当N=0时,ans=1;
所以我们仅仅须要找到最大海拔值Max+1
那么终于所须要的'w'个数即为
ans+=(Max-h[i])*w[i];
此题一開始着实被__int64坑了一把,该站点仅支持long long,并且输入输出的时候还得用%lld,不然居然是Presentation Error,这就不能忍了,凭什么不是Wrong Answer!!!好吧,此题会超int
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<deque> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 using namespace std; const int N = 100000 + 10; const int M = 40; const int inf = 100000000; const int mod = 2009; long long h[N],w[N]; int main() { int n,i; long long ans,Max; while(~scanf("%d",&n)) { Max=ans=0; for(i=0;i<n;i++) { scanf("%lld%lld",&h[i],&w[i]); Max=max(Max,h[i]); } Max++; for(i=0;i<n;i++) ans+=(Max-h[i])*w[i]; long long s=1; printf("%lld\n",max(ans,s)); } return 0; }菜鸟成长记