四川大学第二届SCUACM新生赛(同步赛)题解

周末没事干,就不要脸地去一边吃饭一边看学弟沈阳拿银一边水了个比赛,水都水了,简单写个题解。

比赛链接

A,丁姐姐喜欢Fibonacci。签到1,斐波那契%3 1 1 0 1 1 0 1 1 0。。。,判断模3等于0就好了

 1 #include<cstdio>
 2 typedef long long ll;
 3 int main(){
 4     ll n;
 5     while(~scanf("%lld",&n)){
 6         if(n%3==0) printf("\"odd\"\n");
 7         else printf("\"even\"\n");
 8     }
 9     return 0; 
10 } 
A

B.丁姐姐喜欢LCS。签到2.找最长的首尾相接的,那直接枚举答案的长度,然后进行暴力匹配。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=2e3+11;
 6 char a[N],b[N];
 7 int main(){
 8     while(~scanf("%s%s",a+1,b+1)){
 9         int lena=strlen(a+1),lenb=strlen(b+1),ans=0;
10         for(int i=min(lena,lenb),j;i>=1;i--){
11             for(j=1;j<=i;j++) if(b[j]!=a[lena-i+j]) break;
12             if(j>i){
13                 ans=i;
14                 break;
15             }
16         }
17         if(ans==0) printf("\"NULL!\"");
18         else for(int i=1;i<=ans;i++) printf("%c",b[i]);
19         printf("\n");
20     }
21     return 0;
22 } 
B

C.俏兔子大战傻贼鹰-Easy Version。简单模拟,判断一下有三张的牌的个数还有两张牌的个数即可,话说数据有点水,居然没有六张一样的牌

 1 #include<cstdio>
 2 #include<cstring> 
 3 char op,s[52];
 4 int num[10][5];
 5 int main(){
 6     int t,lens;
 7     while(~scanf("%d",&t)){
 8         getchar();
 9         scanf("%c",&op);
10         while(t--){
11             scanf("%s",s);
12             lens=strlen(s);
13             bool flag=true;
14             for(int i=0;i<lens;i+=2){
15                 int op1=s[i]-'0',op2;
16                 if(s[i+1]=='S') op2=0;
17                 else if(s[i+1]=='T') op2=1;
18                 else op2=2;
19                 num[op1][op2]++;
20                 if(s[i+1]==op){
21                     flag=false;
22                     break;
23                 }
24             }
25             int num1=0,num2=0;
26             for(int i=1;i<=9;i++)
27                 for(int j=0;j<3;j++){
28                     if(num[i][j]==3) num1++;
29                     else if(num[i][j]==2) num2++;
30                     num[i][j]=0;
31                 }
32             if(flag&&((num1==4&&num2==1)||num2==7)) printf("Yes\n");
33             else printf("No\n");
34         }
35     }
36     return 0;
37 }
C

D.俏兔子大战傻贼鹰-Hard Version。简单模拟2,改一下判断条件那里即可,优先三张连续的再考虑三张一样的。

 1 #include<cstdio>
 2 #include<cstring> 
 3 char op,s[52];
 4 int num[10][5];
 5 int main(){
 6     int t,lens;
 7     while(~scanf("%d",&t)){
 8         getchar();
 9         scanf("%c",&op);
10         while(t--){
11             scanf("%s",s);
12             lens=strlen(s);
13             bool flag=true;
14             for(int i=0;i<lens;i+=2){
15                 int op1=s[i]-'0',op2;
16                 if(s[i+1]=='S') op2=0;
17                 else if(s[i+1]=='T') op2=1;
18                 else op2=2;
19                 num[op1][op2]++;
20                 if(s[i+1]==op){
21                     flag=false;
22                     break;
23                 }
24             }
25             int num1=0,num2=0;
26             for(int i=1;i<=9;i++)
27                 for(int j=0;j<3;j++){
28                     if(i<=7){
29                         while(num[i][j]&&num[i+1][j]&&num[i+2][j]){
30                             num[i][j]--;
31                             num[i+1][j]--;
32                             num[i+2][j]--;
33                             num1++;
34                         }
35                     }
36                     if(num[i][j]>=3) num1++;
37                     if(num[i][j]==2) num2++;
38                     num[i][j]=0;
39                 }
40             if(flag&&((num1==4&&num2==1)||num2==7)) printf("Yes\n");
41             else printf("No\n");
42         }
43     }
44     return 0;
45 }
D

E.[模板]欧拉筛。简单数学题,用不到欧式筛,埃式筛即可,不过我平时都是用欧式筛。入手点,在模数p是1e5级别的数,大于模数的阶乘取模后都为0就不用考虑了,所以先预处理出1e5内素数,然后for到min(n,p)来计算答案就好。

 1 #include<cstdio>
 2 typedef long long ll;
 3 const int N=1e5+11;
 4 bool nop[N];
 5 int pn,pri[N];
 6 void init(){
 7     for(int i=2;i<N;i++){
 8         if(!nop[i]) pri[pn++]=i;
 9         for(int j=0;j<pn;j++){
10             if(1ll*i*pri[j]>=N) break;
11             nop[i*pri[j]]=true;
12             if(i%pri[j]==0) break;
13         }
14     }
15 }
16 int main(){
17     init();
18     int t,n,p;
19     scanf("%d",&t);
20     while(t--){
21         scanf("%d%d",&n,&p);
22         ll jc=1,ans=0;
23         for(int i=2;i<=p&&i<=n;i++){
24             jc=jc*i%p;
25             if(!nop[i]) ans=(ans+jc)%p;
26         }
27         printf("%d\n",ans);
28     } 
29     return 0;
30 }
E

F.[模板]后缀自动机。思维题。要是真的后缀自动机我还真不会。首先我们肯定可以想到是用S的最小后缀去跟T的最小前缀比较即可,S的最小后缀怎么求,后缀自动机?最小表示法?好像都不会,那么我们看T的最小前缀,那不就是第一个字符吗,所以只要判断S中有字典序小于T的第一个字符的字符即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 const int N=2e5+11;
 4 char s1[N],s2[N];
 5 int main(){
 6     int t;
 7     scanf("%d",&t);
 8     while(t--){
 9         scanf("%s%s",s1,s2);
10         int lens1=strlen(s1);
11         bool flag=false;
12         for(int i=lens1-1;i>=0;i--) if(s2[0]>s1[i]){
13             flag=true;
14             break;
15         }
16         if(flag) printf("YE5\n");
17         else printf("N0\n");
18     }
19     return 0;
20 }
F

G.走迷宫。数学题。可以看出就是螺旋矩阵给出序号求坐标,那么把它划分一层层,第一层的个数就有m+n-1+m-1+n-2也就是2*(n+m-2)个,第二层便是n-2,然后m-2,跟第一场的差便是8个,所以这是个等差数列,那么根据等差数列求和,我们就可以判断出给出的序号在哪一层,然后确定了在哪一层,再根据它在一条边判断即可,需要注意的是n=1,和m=1时的情况。

 1 #include<cstdio>
 2 #include<cmath> 
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 void solve(ll n,ll m,ll k){
 7     if(k>=n*m) k=n*m;
 8     ll d=((n+m)*2-ceil(sqrt((n+m)*(n+m)*4-k*16)))/8; 
 9     d=min(min(n/2,m/2),d);
10     ll x=1+d,y=1+d;
11     k-=(d*(n+m)*4-d*d*8)/2;
12     n-=d*2,m-=d*2;
13     if(!k) y--;
14     else if(n==1) y+=k-1;
15     else if(m==1) x+=k-1;
16     else{
17         if(k<=m) y+=k-1;
18         else if(k<=n+m-1) y+=m-1,x+=k-m;
19         else if(k<=n+m*2-2) x+=n-1,y+=m*2+n-k-2;
20         else x+=(n+m)*2-k-3;
21     }
22     printf("(%d,%d)\n",x,y);
23 }
24 int main(){
25     int t,q;
26     ll n,m,k;
27     scanf("%d",&t);
28     while(t--){
29         scanf("%lld%lld",&n,&m);
30         scanf("%d",&q);
31         while(q--){
32             scanf("%lld",&k);
33             solve(n,m,k+1); 
34         }
35     }
36     return 0;
37 }
G

H.捡金币。二维前缀和,个人感觉最难的一题吧。根据题意我们要求的就是一个菱形里的点权值和,但我只维护过正的矩形的和,没整过菱形的和,那咋办呢。通过点旋转公式,把整个图形旋转45度,它不就正的了吗,这时再维护这个正的二维前缀和即可。点旋转公式可以自行百度,然后旋转之后原先的坐标(x,y)便成了(√2/2(x+y),√2/2(x-y)),然后我们整体放大√2倍,就成了(x+y,x-y),x-y会存在负数,那便再加上y轴的偏移量,最后便是(x+y,x-y+m),因为k的点的绝对值坐标距离,所以不需要方法√2倍,否则要是两点之间的欧式距离的话,则也需要放大√2倍。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 typedef long long ll;
 5 const int N=2e3+11;
 6 ll sum[N][N];
 7 int main(){
 8     int t,n,m,q,x,y,k;
 9     scanf("%d",&t);
10     while(t--){
11         scanf("%d%d",&n,&m);
12         for(int i=0;i<=n+m;i++)
13             for(int j=0;j<=n+m;j++) sum[i][j]=0;
14         for(int i=1;i<=n;i++)
15             for(int j=1;j<=m;j++){
16                 x=i+j;y=i-j+m;
17                 scanf("%lld",&sum[x][y]);
18             }
19         for(int i=1;i<=n+m;i++)
20             for(int j=1;j<=n+m;j++)
21                 sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
22         scanf("%d",&q);
23         int lx,ly,rx,ry;
24         while(q--){
25             scanf("%d%d%d",&x,&y,&k);
26             lx=max(1,x+y-k),ly=max(1,x-y+m-k);
27             rx=min(n+m,x+y+k),ry=min(n+m,x-y+m+k);
28             printf("%lld\n",sum[rx][ry]-sum[rx][ly-1]-sum[lx-1][ry]+sum[lx-1][ly-1]);
29         }
30     }
31     return 0;
32 }
H

I.排序。模拟,弄个结构体,照着题意来即可。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<tr1/unordered_map>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=55;
 7 struct Node{
 8     string name;
 9     int ts,zsj,tj[N],tg[N],sj[N];
10     bool operator<(const Node &n1)const{
11         return ts==n1.ts ? (zsj==n1.zsj ? name<n1.name : zsj<n1.zsj): ts>n1.ts;
12     }
13 }a[N];
14 tr1::unordered_map<string,int> mmp;
15 int main(){
16     int t,n,m;
17     string s;
18     scanf("%d",&t);
19     while(t--){
20         scanf("%d%d",&n,&m);
21         mmp.clear();
22         for(int i=1;i<=m;i++){
23             cin>>s;
24             a[i].name=s;
25             mmp[s]=i;
26             for(int j=1;j<=n;j++){
27                 a[i].ts=a[i].zsj=0;
28                 a[i].tg[j]=a[i].tj[j]=a[i].sj[j]=0;
29             }
30         }
31         int q,id,th,sj;
32         scanf("%d",&q);
33         while(q--){
34             cin>>s;id=mmp[s];
35             cin>>sj;cin>>s;th=s[0]-'A'+1;
36             cin>>s;
37             if(a[id].tg[th]) continue;
38             if(s[0]=='A'){
39                 a[id].tg[th]=1;a[id].ts++;
40                 a[id].sj[th]=sj;
41                 a[id].zsj+=sj+20*a[id].tj[th];
42                 a[id].tj[th]++;
43             }else if(s[0]!='C') a[id].tj[th]++;
44         }
45         sort(a+1,a+1+m);
46         for(int i=1,ra=1;i<=m;i++){
47             if(i>1&&(a[i].ts!=a[i-1].ts||a[i].zsj!=a[i-1].zsj)) ra=i;
48             cout<<ra<<" "<<a[i].name<<" "<<a[i].ts<<" "<<a[i].zsj;
49             for(int j=1;j<=n;j++){
50                 printf(" ");
51                 if(a[i].tg[j]){
52                     printf("+%d(%d)",a[i].tj[j],a[i].sj[j]);
53                 }else printf("-%d",a[i].tj[j]);
54             }
55             printf("\n");
56         }
57         if(t) printf("\n");
58     }
59     return 0;
60 } 
I

J.n=a*b*c,数学题,由x*y<=n有x<=√n||y<=√n,那么√n枚举两个数,然后求第三个数,再更新一下答案即可。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5 int main(){
 6     int t,n,m;
 7     scanf("%d",&t);
 8     while(t--){
 9         scanf("%d",&n);m=(int)sqrt(n);
10         int a=0,b=-1,c=n+1,aa,bb,cc;
11         for(int i=2;i<=m;i++)
12             for(int j=2;j<=m;j++){
13                 if(n%(i*j)!=0||i*j==n) continue;
14                 aa=min(min(i,j),n/(i*j));
15                 cc=max(max(i,j),n/(i*j));
16                 bb=i+j+n/(i*j)-aa-cc;
17                 if(cc-aa<c-a||(cc-aa==c-a&&aa<a)) a=aa,b=bb,c=cc;
18             }
19         if(a==0) printf("No solution\n");
20         else printf("%d=%d*%d*%d\n",n,a,b,c); 
21     } 
22     return 0;
23 }
J

K.梅森素数,3 7 31 127 8191,就这样吧。

L.双流机场。思维题,一开始看错题意了,以为左上角能到其他地方即可,错了一发。然后仔细一看题意是任意两点可达,那就简单了。处于中间的点肯定会有能到达它并且从它出去的路线,所以我们只需要判读四个角不是没有进入的路线,或者没有出去的路线即可。

 1 #include<cstdio>
 2 const int N=1e5+11;
 3 char a[N],b[N];
 4 int main(){
 5     int t,n,m;
 6     scanf("%d",&t);
 7     while(t--){
 8         scanf("%d%d",&n,&m);
 9         scanf("%s%s",a+1,b+1);
10         if(a[1]!=b[1]) printf("Sad\n");
11         else if(a[1]==b[m]) printf("Sad\n");
12         else if(a[n]==b[1]) printf("Sad\n");
13         else if(a[n]!=b[m]) printf("Sad\n");
14         else printf("Happy\n");
15     }
16     return 0;
17 }
L

M.lglg说要有题,于是便有了题。额,打表题,垃圾精度,怪恶心的,根据题目打表来观察即可,但精度很恶心恶心恶心。就小于3输出0,小于29输出1,小于11789输出2,其他输出3。

猜你喜欢

转载自www.cnblogs.com/LMCC1108/p/11885035.html