2014苏州大学新生赛11月新生赛简单题解

比赛场链接:http://acm.hdu.edu.cn/diy/contest_show.php?cid=25601

对于本次新生赛感觉还是挺满意的(萌萌哒),题目挺好(除了个别坑),榜单挺好看,我们的新生做的和我预期差不多,希望大家能再接再厉,无论好与不好,继续加油!不废话啦,题解写上:

前四道题目是通神出的

1.直接输出(A+B)*32767)%C

一个是需要long long,另一个是16位有符号整数能表示的最大值是32767有人不知道,有人说这个题目有什么意思,其实就是想考你这个计算机基础知识。

2.考虑到负数是((A-B)%C+C)%C

题目没有标注负数情况是有些坑,但即使说了负数有些人也不知道这个同余公式。

3.答案((A%C)*(B%C))%C

这题按通神原本意思不应该是这样的,结果C小了,long long给水过去了,这样就和第二题取模运算的知识点重复了。

4.通神的防AK题

验题时我感觉不会,直接忽略这道题目,现在想想其实挺简单的,要注意到a的范围是9以内,就是大胆的数组模拟大数*i,然后结果每个保存在数组里面,看了代码就能理解了。

 1 #include <cstdio>
 2 #include <cstring>
 3 int ans[4005],cnt[10][4005];
 4 int main(){
 5     int a,b,i,j,add,kkk=1,T;
 6     memset(cnt,0,sizeof(cnt));
 7     for(b=1;b<=4000;b++)cnt[1][b]=1;
 8     for(a=2;a<=9;a++){
 9         memset(ans,0,sizeof(ans));
10         ans[1]=a;
11         cnt[a][1]=a;
12         ans[0]=1;
13         for(b=2;b<=4000;b++){
14             i=1;add=0;
15             for(i=1;i<=ans[0];i++){
16                 ans[i]=ans[i]*a+add;
17                 add=ans[i]/10;
18                 ans[i]=ans[i]%10;
19             }
20             if(add){
21                 ans[0]++;
22                 ans[ans[0]]=add;
23             }
24             for(j=1;j<=i+2;j++)cnt[a][b]+=ans[j];
25         }
26     }
27     scanf("%d",&T);
28     for(i=1;i<=T;i++){
29         scanf("%d%d",&a,&b);
30         printf("Case #%d: %d\n",i,cnt[a][b]);
31     }
32     return 0;
33 }
展开代码

5.答案是a,b最大值,无坑良心水题,要是把我的题目放前面估计榜单会好看一些。

6.这个题目是自己之前看到过的改变而来,有些同学以为答案就是log2(x),为了让大家看到我的良心题无坑,特地把9的样例答案2写上去了。

这样想,我们假设要测n个钻石,1.如果n能被3整除那就均分成3堆,然后随意拿两堆出来测肯定可以得到假钻石在哪一堆,所以问题转化为f[n/3]+1。2.如果n不能被3整除就分成n/3的三堆,然后剩下一个就放在任意一堆,两个就随意找两堆各放一个,这样拿相同的两堆出来就知道假钻石在哪一堆,显然最差也就是在多的那堆,即为f[n/3+1]+1。这是一种做法,其实,最后我们可以发现,答案就是log3(x)向上取整。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int f[210000];
 7 int main()
 8 {
 9     f[2]=f[3]=1;
10     for(int i=4;i<=100000;i++)
11     {
12         if(i%3==0) f[i]=f[i/3]+1;
13         else f[i]=f[i/3+1]+1;
14     }
15     int n;
16     while(scanf("%d",&n)==1)
17     {
18         printf("%d\n",f[n]);
19     }
20     return 0;
21 }
展开代码

7.这个博弈其实只要想通了就会觉得很简单。

自己在纸上画一个圈,当A取过1或2个棋子后所有剩余棋子正好形成了一条链。这样B在剩下棋子中选择,如果剩下棋子为奇数B只要拿走中间一个,所有棋子即被拆成两个一模一样的链,接下来无论A怎么取,B在另一堆都能和A取的一样直到B拿走最后一个棋子。如果剩下棋子为偶数B只需要拿走中间两个棋子,这样就又形成了两个相同的链,B和上面一样。所以我们得到结论,除非n是1和2A可以直接取完,否则B总能取到最后一个棋子。

8.为了让大家做好入门经典模拟题,所以出了这道日期相差天数题目,唯一的坑在于两个日期大小不一定。

最简洁的莫过于加一个0年0月0日的新日期,计算两个日期到新日期差,然后答案即为差。

 1 #include<cstdio>
 2 #include <algorithm>
 3 int month[20]={0,31,28,31,30,31,30,31,31,30,31,30,31};
 4 int run(int x){if((x%4==0&&x%100!=0)||x%400==0)return 1;else return 0;}
 5 int sum(int x,int y,int z,int ans){
 6     for(int i=0;i<=x-1;i++)if(run(i))ans+=366;else ans+=365;
 7     if(run(x))month[2]=29;else month[2]=28;
 8     for(int i=1;i<=y-1;i++)ans+=month[i];ans+=z;
 9     return ans;
10 }
11 int main(){
12     int x,y,z,a,b,c;
13     while(scanf("%d%d%d%d%d%d",&x,&y,&z,&a,&b,&c)!=EOF)
14         printf("%d\n",abs(sum(x,y,z,0)-sum(a,b,c,0)));
15     return 0;
16 }
展开代码

9.这是本场比赛唯一一道算法题了,额毕竟要学习一些新东西。本题需要用到快排+二分,如果不知道这个知识点可以先去百度学学。

首先我们来看k不为0的情况,那么把四个数组都加一个0表示这个数组中这个数不取,这样把A数组每位数+B数组每位数放在一个新的n×n的数组V1里面,sort排序,同理把C数组每位数+D数组每位数放在一个新的V2的数组里面,sort排序,这样对于V1里面的每个数,二分查找V2里面有没有k-V1[i]的数,只要找到一个就是YES,都没找到就是NO。再来看k为0的时候,这个时候我们假设还用上面那个方法,这个时候就出现了一个问题,最终你可能一个数都没取,这样就不符合它的至少有一个人参加要求,所以我们需要另外加了flag变量来判断最终得到的k是否是所有另外加上去的四个0构成的,是就是NO,否则就是YES。具体一些细节的处理和技巧可以看看代码,觉得鹏神的代码更好理解所以把他的代码贴出来。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 int n,k;
 8 int v[5][2010];
 9 int v1[2010 * 2010];
10 int v2[2010 * 2010];
11 int cnt1,cnt2;
12 
13 int main(){
14   while(scanf("%d%d",&n,&k) != EOF){
15     if(n == 0){
16       printf("NO\n");
17       continue;
18     }
19     int flag1 = 0,flag2 = 0;
20     cnt1 = cnt2 = 0;
21     v1[++cnt1] = 0;
22     v2[++cnt2] = 0;
23     for(int i = 1; i <= 4; ++i){
24       for(int j = 1; j <= n; ++j){
25         scanf("%d",&v[i][j]);
26         if(v[i][j] == 0){
27           if(i < 3) flag1 = 1;
28           else flag2 = 1;
29         }
30       }
31     }
32     // v[1] , v[2] 只取其一
33     for(int i = 1; i <= n; ++i){
34       v1[++cnt1] = v[1][i];
35       v1[++cnt1] = v[2][i];
36       v2[++cnt2] = v[3][i];
37       v2[++cnt2] = v[4][i];
38     }
39     //v[1] , v[2] 都取
40     for(int i = 1; i <= n; ++i){
41       for(int j = 1; j <= n; ++j){
42         v1[++cnt1] = v[1][i] + v[2][j];
43         if(!v1[cnt1]) flag1 = 1;
44         v2[++cnt2] = v[3][i] + v[4][j];
45         if(!v2[cnt2]) flag2 = 1;
46       }
47     }
48     sort(v1 + 1,v1 + cnt1 + 1);
49     sort(v2 + 1,v2 + cnt2 + 1);
50     int flag = 0;
51     for(int i = 1; i <= cnt1; ++i){
52       int pos = lower_bound(v2 + 1,v2 + cnt2 + 1,k - v1[i]) - v2;
53       if(v1[i] + v2[pos] == k){
54         if(v1[i] == 0 && v2[pos] == 0 && flag1 == 0 && flag2 == 0)
55           continue;
56          flag = 1;
57         break;
58       }
59     }
60     if(flag) printf("YES\n");
61     else printf("NO\n");
62   }
63   return 0;
64 }
View Code

10.一个找规律的水题,就是对于所有的五位数,只要第一位×第二位=45位,然后第一位+第二位个位数为第三位,则符合题目的规律,从小到大输出所有符合要求的五位数。

至此,第一场新生赛over,好累TUT。

posted on 2014-11-27 01:05  xiao_xin  阅读(259)  评论(0编辑  收藏  举报

导航