2017/9/15模拟赛
游戏(game)
【问题描述】
小R和小H在玩某个双人联机小游戏,一开始两人所操控的角色各有1点力量值,而在游戏中,每通过一关都会掉落一些力量强化道具。奇怪的是,明明是双人小游戏,每关却都会掉落3个相同的力量强化道具,于是两人决定每关每人先拿一个,剩下一个猜拳决定给谁。一个力量强化道具能使一个角色的力量值变为原来的若干整数倍,同一关卡掉落的道具倍率都相同,而不同的关卡可能不同。小R从攻略上找到了一些会产生特殊效果的力量值组合,他想知道哪些组合是按他们的道具分配方式有可能在通过某关时达成的。
【输入格式】
第一行一个正整数n,表示力量值组合的个数。
接下来n行,每行两个非负整数ai,bi,表示一个力量值组合。
【输出格式】
输出共n行,每行一个”YES”或”NO”表示是否能够达成。
【样例输入】
2
2 4
1 8
【样例输出】
YES
NO
【数据范围】
本题共10个测试点,其中第x个测试点满足n<=,ai,bi<=10^(x-1)。
题解:把a和b相乘,注意特判0的情况。
代码如下:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 using namespace std; 5 int main() 6 { 7 freopen("game.in","r",stdin); 8 freopen("game.out","w",stdout); 9 int n,a,b,c; 10 scanf("%d",&n); 11 while(n--){ 12 scanf("%d%d",&a,&b); 13 if(!a&&!b){puts("YES");continue;} 14 if(!a||!b){puts("NO");continue;} 15 c=int(pow(1LL*a*b,1.0/3)+0.5); 16 puts(1LL*c*c*c==1LL*a*b&&a%c==0&&b%c==0?"YES":"NO"); 17 } 18 return 0; 19 }
数字(number)
【问题描述】
小R被某人要求做一个报告,报告中要用到一些数据,可惜小R没有,只好自己瞎编一个,于是他随便滚了下键盘,出来一个奇怪的数字。因为明眼人都看的出这个数字是乱打的,所以小R打算强化一下这个数字的可信度,首先他把这一大长串数字分成了n个,然后他决定选出其中k个,把它们乘起来得到最后的数字。众所周知,一个数字末尾的0越多越高大上,所以小R想要最大化得到的数字末尾0的数量。按照套路,请你解决一下。
【输入格式】
第一行两个正整数n和k。
接下来n行,每行一个非负整数ai,表示给出的数字。
【输出格式】
输出一个整数,表示答案。
【样例输入】
3 2
20
50
80
【样例输出】
3
【数据范围】
对于20%的数据,n<=15,ai<=10;
对于30%的数据,n<=25;
对于50%的数据,n<=50,ai<=100;
对于70%的数据,n<=100,ai<=10^9;
对于100%的数据,n<=200,ai<=10^18。
题解:统计出每个数因数中2和5的个数,并把所有数的2、5因数加起来,倒过来贪心即可。
PS:不是正解- -,只有90的暴力。
代码如下:
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 int n,m,c2[201],c5[201],sum2,sum5; 5 bool vis[201],flag; 6 long long a[201]; 7 struct node{int n2,n5,mn,num;}tmp; 8 int main() 9 { 10 freopen("number.in","r",stdin); 11 freopen("number.out","w",stdout); 12 scanf("%d%d",&n,&m); 13 for(int i=1;i<=n;i++){ 14 scanf("%lld",&a[i]); 15 if(a[i]==0){flag=true;continue;} 16 while(!(a[i]%2)){c2[i]++;a[i]/=2;} 17 while(!(a[i]%5)){c5[i]++;a[i]/=5;} 18 sum2+=c2[i]; sum5+=c5[i]; 19 } 20 for(int i=1;i<=n-m;i++){ 21 tmp.n2=0; tmp.n5=0; tmp.mn=0; 22 for(int j=1;j<=n;j++){ 23 if(vis[j]==true) continue; 24 int now2=sum2-c2[j],now5=sum5-c5[j]; 25 int nowm=min(now2,now5); 26 if(nowm>tmp.mn||(nowm==tmp.mn&&(now2>tmp.n2||now5>tmp.n5))){ 27 tmp.n2=now2; tmp.n5=now5; tmp.mn=nowm; tmp.num=j; 28 } 29 } 30 sum2=tmp.n2; sum5=tmp.n5; vis[tmp.num]=true; 31 } 32 if(min(sum2,sum5)==0&&flag){printf("1");return 0;} 33 printf("%d",min(sum2,sum5)); 34 return 0; 35 }
餐厅(restaurant)
【问题描述】
小R最近在玩一款模拟餐厅打工的游戏,其中有一个叠盘子的小游戏小R很喜欢。这个小游戏是这样的:有一个放盘子的机器会在一条直线上运动,机器里装着n个盘子,其中第i个盘子半径为ri,并且如果要放下该盘子,盘子的中心必须放在直线上xi的位置上,小R可以决定放下哪些盘子和放下这些盘子的顺序,盘子可以放在空位上,或者叠在一个上面没有其他盘子的盘子上,但要求被叠的盘子必须包含要叠上去的盘子。小R想要让叠出的盘子尽量高,请你计算出最高的一叠最多能叠几个盘子。
【输入格式】
第一行一个正整数n,表示盘子数。
接下来n行,每行两个正整数ri和xi。
【输出格式】
输出一个整数,表示答案。
【样例输入】
3
3 5
2 4
2 6
【样例输出】
2
【数据范围】
对于20%的数据,n<=10;
对于50%的数据,n<=1,000;
对于100%的数据,n<=100,000,ri,xi<=10^9。
题解:把右端点从小到大排序,左端点中的最长不下降子序列即为答案,用线段树维护。
标程:不存在的。。。