FJUT2017寒假训练二题解
Posted seventh成长中---
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FJUT2017寒假训练二题解相关的知识,希望对你有一定的参考价值。
A题
题意:让你找出唯一的一个四位数,满足对话时的要求。
思路:因为是4位数,可以直接从1000-9999遍历一遍,判断是否有唯一的数能满足所有条件,如果不是唯一的或者没有满足条件的数就输出Not sure。特别丑的代码附上。。。
1 #include<stdio.h> 2 int a[10000],b[10000],c[10000]; 3 int main() 4 { 5 int n; 6 while(~scanf("%d",&n)) 7 { 8 if(n==0)break; 9 int i,flag=0,ans,j,k; 10 for(i=1;i<=n;i++) 11 scanf("%d%d%d",a+i,b+i,c+i); 12 for(i=1000;i<=9999;i++) 13 { 14 int a1,a2,a3,a4,i1,i2,i3,i4,bx=0,cx=0,flg=1;///ax代表a[i]的第x个数,ix代表i的第x个数 15 for(j=1;j<=n;j++) 16 { 17 bx=0;cx=0; 18 a1=a[j]/1000; 19 a2=(a[j]/100)%10; 20 a3=(a[j]/10)%10; 21 a4=a[j]%10; 22 i1=i/1000; 23 i2=(i/100)%10; 24 i3=(i/10)%10; 25 i4=i%10; 26 if(a1==i1)///先判断位置正确的 27 cx++; 28 if(a2==i2) 29 cx++; 30 if(a3==i3) 31 cx++; 32 if(a4==i4) 33 cx++; 34 if(a1==i1)///这里如果判和i中的一个数相等,就让i中的那个数为11,就不会再和下个数匹配了,防止出现当类似ai=1111,i=1234的时候a1,a2,a3,a4都和i1匹配成功的情况。 35 { 36 bx++; 37 i1=11; 38 } 39 else if(a1==i2) 40 { 41 bx++; 42 i2=11; 43 } 44 else if(a1==i3) 45 { 46 bx++; 47 i3=11; 48 } 49 else if(a1==i4) 50 { 51 bx++; 52 i4=11; 53 } 54 if(a2==i1) 55 { 56 bx++; 57 i1=11; 58 } 59 else if(a2==i2) 60 { 61 bx++; 62 i2=11; 63 } 64 else if(a2==i3) 65 { 66 bx++; 67 i3=11; 68 } 69 else if(a2==i4) 70 { 71 bx++; 72 i4=11; 73 } 74 if(a3==i1) 75 { 76 bx++; 77 i1=11; 78 } 79 else if(a3==i2) 80 { 81 bx++; 82 i2=11; 83 } 84 else if(a3==i3) 85 { 86 bx++; 87 i3=11; 88 } 89 else if(a3==i4) 90 { 91 bx++; 92 i4=11; 93 } 94 if(a4==i1) 95 { 96 bx++; 97 i1=11; 98 } 99 else if(a4==i2) 100 { 101 bx++; 102 i2=11; 103 } 104 else if(a4==i3) 105 { 106 bx++; 107 i3=11; 108 } 109 else if(a4==i4) 110 { 111 bx++; 112 i4=11; 113 } 114 if(bx!=b[j]||cx!=c[j]) 115 { 116 flg=0; 117 break; 118 } 119 } 120 if(flg) 121 { 122 123 ans=i; 124 flag++; 125 } 126 } 127 if(flag==1) 128 printf("%d\\n",ans); 129 else 130 printf("Not sure\\n"); 131 } 132 }
B题
题意:打老鼠,在某一个时刻把所有的老鼠打下去。
思路:对于一个[l,r]区间,一定是从最左或者最右开始打,因为如果你从中间开始打,最后还是要经过最左最右,这时候中间位置会经过两次,所以中间开始一定不是最优方案。这样的话问题就变成了一个区间dp,dp[l][r][1]代表从右边开始打完[l,r]区间的老鼠,dp[l][r][0]代表从左边开始打完[l,r]区间的老鼠,这样的话有状态转移方程:
dp[l][r][0]=min(dp[l+1][r][0]+d[l+1]-d[l],dp[l-1][r][1]+d[r]-d[l])
dp[l][r][1]=min(dp[l][r-1][0]+d[r]-d[l],dp[l][r-1][1]+d[r]-d[r-1])
然后开个数组记忆走过的路线
1 #include<stdio.h> 2 #include<string.h> 3 const int INF=999999999;///INF判断能不能在老鼠爬起来之前打完 4 int t[1000010],d[1000010]; 5 int dp[202][202][2];///dp[i][j][0]代表打完[i,j]区间的老鼠并且停留在左端点用的时间 6 ///dp[i][j][1]代表打完[i,j]区间的老鼠并且停留在右端点用的时间 7 int route[202][202][2];///记录路线的数组为0代表往右走遇见第一个冒出头的老鼠。 8 int main() ///为1代表往左走遇见第一个冒出头的老鼠。 9 { 10 int n; 11 while(~scanf("%d",&n)) 12 { 13 int i,j,l,r,temp; 14 for(i=1;i<=n;i++) 15 scanf("%d",t+i); 16 for(i=1;i<=n;i++) 17 scanf("%d",d+i); 18 memset(dp,0,sizeof(dp)); 19 for(l=2;l<=n;l++) 20 { 21 for(i=1;i<=n-l+1;i++) 22 { 23 j=i+l-1; 24 if(dp[i+1][j][0]+d[i+1]-d[i]<=dp[i+1][j][1]+d[j]-d[i]) 25 { 26 dp[i][j][0]=dp[i+1][j][0]+d[i+1]-d[i]; 27 route[i][j][0]=0; 28 } 29 else 30 { 31 dp[i][j][0]=dp[i+1][j][1]+d[j]-d[i]; 32 route[i][j][0]=1; 33 } 34 if(t[i]<=dp[i][j][0]) 35 dp[i][j][0]=INF; 36 if(dp[i][j-1][0]+d[j]-d[i]<=dp[i][j-1][1]+d[j]-d[j-1]) 37 { 38 dp[i][j][1]=dp[i][j-1][0]+d[j]-d[i]; 39 route[i][j][1]=0; 40 } 41 else 42 { 43 dp[i][j][1]=dp[i][j-1][1]+d[j]-d[j-1]; 44 route[i][j][1]=1; 45 } 46 if(t[j]<=dp[i][j][1]) 47 dp[i][j][1]=INF; 48 } 49 } 50 if(dp[1][n][0]<INF)///判断起始位置 51 { 52 temp=route[1][n][0]; 53 printf("1"); 54 l=2,r=n; 55 } 56 else if(dp[1][n][1]<INF) 57 { 58 temp=route[1][n][1]; 59 printf("%d",n); 60 l=1,r=n-1; 61 } 62 else 63 { 64 printf("Mission Impossible\\n"); 65 continue; 66 } 67 while(l<=r)///路线查找 68 { 69 if(temp==0) 70 { 71 temp=route[l][r][0]; 72 printf(" %d",l++); 73 } 74 else 75 { 76 temp=route[l][r][1]; 77 printf(" %d",r--); 78 } 79 } 80 printf("\\n"); 81 } 82 }
C题
题意:一堆单词,找到第一个为B开头的单词,用其他单词和它连接,使得最后一个连接的单词末尾为M。
思路:直接暴力深搜就好了
1 #include<stdio.h> 2 #include<string.h> 3 char a[1001][1001];///储存字符串 4 int dfs(int fi,int count) 5 { 6 int i,flag=0; 7 char temp=a[fi][0]; 8 a[fi][0]=\'0\';///首字母标记为0,就可以避免单词被重复使用 9 if(a[fi][strlen(a[fi])-1]==\'m\') 10 return 1; 11 for(i=1;i<count;i++) 12 if(a[fi][strlen(a[fi])-1]==a[i][0]) 13 { 14 if(dfs(i,count)) 15 return 1; 16 } 17 a[fi][0]=temp;///回溯还原首字母 18 return 0; 19 } 20 int main() 21 { 22 int n=0,i,j,k; 23 while(~scanf("%s",a[++n])) 24 { 25 if(a[n][0]==\'0\') 26 { 27 int flag=0; 28 for(i=1;i<n;i++) 29 { 30 if(a[i][0]==\'b\') 31 { 32 if(dfs(i,n)) 33 { 34 flag=1; 35 break; 36 } 37 } 38 } 39 if(flag) 40 printf("Yes.\\n"); 41 else printf("No.\\n"); 42 n=0;///字符串重新输入 43 } 44 } 45 }
D题
题意:第一天给一颗糖,第二、三天给两颗糖,第四、五、六天给三颗糖......以此类推
思路:模拟这个给糖的方法来写
第一颗糖 一
第二颗糖 二 三
第三颗糖 四 五 六
第四颗糖 七 八 九 十
以此类推
从这上面我们可以发现当第n天为1 3 6 10的时候,第二天糖都会多给一个,很容易看出1 3 6 10是一个二阶等差数列,通项公式为an=n*(n+1)/2,由此就可以写出下面的代码。
1 #include<stdio.h> 2 int main() 3 { 4 int n; 5 while(~scanf("%d",&n)) 6 { 7 int ans=0,i,r=0; 8 if(n==0)break; 9 for(i=1;i<=n;i++) 10 { 11 if(i>r*(r+1)/2)///判断给的糖数是否要增加 12 r++; 13 ans+=r; 14 } 15 printf("%d %d\\n",n,ans); 16 } 17 }
E题
题意:给你一个1-500000内数字,让你把它所有的因数加起来,求出加起来之后的数。
思路:这个题的询问次数很多,一个一个算的话很容易超时,所有我们这里可以进行一个因子和打表的预处理。
1 #include<stdio.h> 2 int a[500001]; 3 int main() 4 { 5 int i,j; 6 for(i=1;i<=250000;i++) 7 { 8 for(j=i*2;j<=500000;j+=i) 9 a[j]+=i; 10 } 11 int t; 12 scanf("%d",&t); 13 while(t--) 14 { 15 int c; 16 scanf("%d",&c); 17 printf("%d\\n",a[c]); 18 } 19 }
以上是关于FJUT2017寒假训练二题解的主要内容,如果未能解决你的问题,请参考以下文章