2015 Multi-University Training Contest 9
1001 Expression
式子不好推啊。见官方题解。
式子知道就方便了。处理好组合数和阶乘。
按区间长度从小到大递推完就好。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 # define maxn 105 6 typedef long long LL; 7 const LL mod=1e9+7; 8 LL fac[maxn]={1},C[maxn][maxn]; 9 LL a[maxn],dp[maxn][maxn]; 10 char op[maxn]; 11 12 int main(void) 13 { 14 for(int i=1;i<maxn;i++) fac[i]=(fac[i-1]*(LL)i)%mod; 15 for(int i=0;i<maxn;i++) C[i][0]=(LL)1; 16 for(int i=1;i<maxn;i++) 17 for(int j=1;j<=i;j++) 18 C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; 19 int n; 20 while(~scanf("%d",&n)) 21 { 22 memset(dp,0,sizeof(dp)); 23 for(int i=1;i<=n;i++) scanf("%I64d",a+i); 24 scanf("%s",op+1); 25 for(int i=1;i<=n;i++) dp[i][i]=a[i]; 26 for(int len=2;len<=n;len++) 27 { 28 for(int s=1;s+len-1<=n;s++) 29 { 30 for(int m=s;m<s+len-1;m++) 31 { 32 LL tem; 33 if(op[m]=='*') tem=dp[s][m]*dp[m+1][s+len-1]; 34 else if(op[m]=='+') tem=dp[s][m]*fac[s+len-m-2]+dp[m+1][s+len-1]*fac[m-s]; 35 else tem=dp[s][m]*fac[s+len-m-2]-dp[m+1][s+len-1]*fac[m-s]; 36 dp[s][s+len-1]+=tem%mod*C[len-2][m-s]%mod; 37 } 38 dp[s][s+len-1]=(dp[s][s+len-1]%mod+mod)%mod; 39 } 40 } 41 printf("%I64d\n",dp[1][n]); 42 } 43 return 0; 44 }
1002 Hack it!
1003 GCD Tree
1004 Too Simple
果然还是图样。置换顺序乘反了。
比赛wa到底。拿了数据才知道错在哪。 QAQ。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 typedef long long LL; 6 const LL mod=1e9+7; 7 int a[101][101],vis[101]; 8 LL fac[101]={1}; 9 10 LL qpow(LL a,int b) 11 { 12 LL d=(LL)1,t=a; 13 while(b) 14 { 15 if(b%2) d=(d*t)%mod; 16 b/=2; 17 t=(t*t)%mod; 18 } 19 return d; 20 } 21 22 int main(void) 23 { 24 for(int i=1;i<=100;i++) fac[i]=(fac[i-1]*LL(i))%mod; 25 int n,m; 26 while(~scanf("%d%d",&n,&m)) 27 { 28 int ok=1,cnt=0; 29 for(int i=1;i<=m;i++) 30 { 31 scanf("%d",&a[i][1]); 32 if(a[i][1]==-1) cnt++; 33 else 34 { 35 for(int j=2;j<=n;j++) scanf("%d",&a[i][j]); 36 memset(vis,0,sizeof(vis)); 37 for(int j=1;j<=n;j++) vis[a[i][j]]++; 38 for(int j=1;j<=n;j++) if(vis[j]!=1) ok=0; 39 } 40 } 41 if(!cnt) for(int i=1;i<=n;i++) 42 { 43 int pos=i; 44 for(int j=m;j>0;j--) pos=a[j][pos]; 45 if(pos!=i) ok=0; 46 } 47 if(!ok) puts("0"); 48 else 49 { 50 LL ans=1; 51 if(cnt) ans=qpow(fac[n],cnt-1); 52 printf("%I64d\n",ans); 53 } 54 } 55 return 0; 56 }
1005 Arithmetic Sequence
以每个点为i。处理一下向前向后能延伸的最大距离。
d1≠d2时。答案为sigma(pre[i]*suf[i])。
d1=d2时。pre[i]相当于以i为右端点的区间数。答案为sigma(pre[i])。
1 # include <iostream> 2 # include <cstdio> 3 using namespace std; 4 typedef long long LL; 5 const int maxn=100100; 6 int a[maxn],pre[maxn],suf[maxn]; 7 8 int main(void) 9 { 10 int n,d1,d2; 11 while(~scanf("%d%d%d",&n,&d1,&d2)) 12 { 13 for(int i=1;i<=n;i++) scanf("%d",a+i); 14 pre[1]=1; suf[n]=1; 15 for(int i=2;i<=n;i++) 16 { 17 if(a[i]==a[i-1]+d1) pre[i]=pre[i-1]+1; 18 else pre[i]=1; 19 } 20 for(int i=n-1;i>0;i--) 21 { 22 if(a[i]==a[i+1]-d2) suf[i]=suf[i+1]+1; 23 else suf[i]=1; 24 } 25 LL ans=0; 26 if(d1==d2) for(int i=1;i<=n;i++) ans+=(LL)pre[i]; 27 else for(int i=1;i<=n;i++) ans+=(LL)pre[i]*(LL)suf[i]; 28 printf("%I64d\n",ans); 29 } 30 return 0; 31 }
1007 Travelling Salesman Problem
n或者m为奇数时必然能走完。
全偶数时选择行标加列标为奇数的格子中最小的格子不走。其余都能走。
(因为是从偶数格子出发到偶数格子终止的。所以不存在只选一个行标加列标为偶数的格子不走。其他格子都走的情况。)
具体做法是。设选中格子坐标为(i,j)。如果i为奇。可以先走到(i,j-1)。再绕过选中格子。绕到(i,j+2)。就转变为一边为奇数的情况了。
同理i为偶数先走到(i-1,j)。绕到(i+2,j)。按奇数边的走完。
要注意选中格子i==n或者j==m的情况要特判一下。
【代码丑- -】
1 # include <iostream> 2 # include <cstdio> 3 using namespace std; 4 # define INF 2147483647 5 int n,m,map[101][101]; 6 7 void Print_char(int len,char c) 8 { 9 for(int i=0;i<len;i++) putchar(c); 10 } 11 12 void ans_print(int x,int y) 13 { 14 if((n-x)%2==0) 15 { 16 int len=m-y; 17 for(int i=x;i<n;i+=2) 18 { 19 Print_char(len,'R'); 20 putchar('D'); 21 Print_char(len,'L'); 22 putchar('D'); 23 } 24 Print_char(len,'R'); 25 } 26 else 27 { 28 int len=n-x; 29 for(int i=y;i<m;i+=2) 30 { 31 Print_char(len,'D'); 32 putchar('R'); 33 Print_char(len,'U'); 34 putchar('R'); 35 } 36 Print_char(len,'D'); 37 } 38 printf("\n"); 39 return; 40 } 41 42 int main(void) 43 { 44 while(~scanf("%d%d",&n,&m)) 45 { 46 int sum=0; 47 for(int i=1;i<=n;i++) 48 { 49 for(int j=1;j<=m;j++) 50 { 51 scanf("%d",&map[i][j]); 52 sum+=map[i][j]; 53 } 54 } 55 if(n%2||m%2) 56 { 57 printf("%d\n",sum); 58 ans_print(1,1); 59 continue; 60 } 61 int Min=INF,x,y; 62 for(int i=1;i<=n;i++) 63 for(int j=1;j<=m;j++) 64 if((i+j)%2==1&&map[i][j]<Min) 65 {Min=map[i][j];x=i;y=j;} 66 printf("%d\n",sum-Min); 67 int xx=1,yy=1; 68 if(x%2==0) 69 { 70 while(xx<x-1) 71 { 72 int len=m-yy; 73 Print_char(len,'R'); 74 putchar('D'); 75 Print_char(len,'L'); 76 putchar('D'); 77 xx+=2; 78 } 79 while(yy<y) 80 { 81 int len=n-xx; 82 Print_char(len,'D'); 83 putchar('R'); 84 Print_char(len,'U'); 85 putchar('R'); 86 yy+=2; 87 } 88 if(x<n) 89 { 90 Print_char(m-yy,'R'); 91 putchar('D'); 92 for(int i=m;i>yy;i--) 93 { 94 if((i-yy)%2) printf("DL"); 95 else printf("UL"); 96 } 97 putchar('D'); 98 ans_print(x+2,y); 99 } 100 else 101 { 102 putchar('R'); 103 ans_print(x-1,y+1); 104 } 105 } 106 else 107 { 108 while(xx<x) 109 { 110 int len=m-yy; 111 Print_char(len,'R'); 112 putchar('D'); 113 Print_char(len,'L'); 114 putchar('D'); 115 xx+=2; 116 } 117 while(yy<y-1) 118 { 119 int len=n-xx; 120 Print_char(len,'D'); 121 putchar('R'); 122 Print_char(len,'U'); 123 putchar('R'); 124 yy+=2; 125 } 126 if(y<m) 127 { 128 Print_char(n-x,'D'); 129 putchar('R'); 130 for(int i=n;i>xx;i--) 131 { 132 if((i-xx)%2) printf("RU"); 133 else printf("LU"); 134 } 135 putchar('R'); 136 ans_print(x,y+2); 137 } 138 else 139 { 140 putchar('D'); 141 ans_print(x+1,y-1); 142 } 143 } 144 } 145 return 0; 146 }
1010 Sometimes Naive