第五届省赛C:colourful cupcakes
N=60.
天真如我,居然在考虑搜索的算法/(ㄒoㄒ)/~~三叉树……3^60=10^24+……不计算考虑复杂度都是耍流氓>_<
再算了一下,感觉O(N^4)可以试试,60^4=10^8+……但是毕竟最差的情况嘛>_<,再看一下题解果然是4重循环的……计数……dp……(想到之前坚信的搜索不禁(*/ω\*))
中间看到了一个三次动规六个方程的算法。
做麻烦了。
学长思路好快。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<string> #include<map> #include<vector> using namespace std; #define clr(c,x) memset(c,x,sizeof(c)); #define rep(i,f,t) for(int i = (f), _end = (t); i <= _end; ++i) #define debug(x) cout<<"debug "<<x<<endl; typedef long long int64; const int mod = 1000000007; int n,A,B,C; char str[55]; int cnt[3]; int64 d[55][55][55][3]; int solve(int x){ //表示固定第一块蛋糕为x类的方案数。 clr(d,0); if(x==0) d[1][1][0][0] = 1; else if(x == 1) d[1][0][1][1] = 1; else d[1][0][0][2] = 1; rep(i,2,n)rep(a,0,min(i,A))rep(b,0,min(B,i-a)){ int c = i-a-b; if(c > C)continue; if( (a==0)+(b==0)+(c==0) >= 2)continue; //abc出现两个以上的0为无效状态 if(a && ((i!=2 && i!=n) || x!=0))d[i][a][b][0] = ( d[i][a][b][0] + d[i-1][a-1][b][1] + d[i-1][a-1][b][2] ) % mod; if(b && ((i!=2 && i!=n) || x!=1))d[i][a][b][1] = ( d[i][a][b][1] + d[i-1][a][b-1][0] + d[i-1][a][b-1][2] ) % mod; if(c && ((i!=2 && i!=n) || x!=2))d[i][a][b][2] = ( d[i][a][b][2] + d[i-1][a][b][0] + d[i-1][a][b][1] ) % mod; } return ( d[n][A][B][0] + d[n][A][B][1] + d[n][A][B][2] ) % mod; } int main(){ int casn; scanf("%d",&casn); while(casn--){ scanf("%s",str); n = strlen(str); A = cnt[0] = count(str,str+n,‘A‘); B = cnt[1] = count(str,str+n,‘B‘); C = cnt[2] = count(str,str+n,‘C‘); int64 ans[3];clr(ans,0); rep(i,0,3)if(cnt[i])ans[i] = solve(i); ans[0] += ans[1]+ans[2]; ans[0] %= mod; printf("%d\n",ans[0]); } return 0; }
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <map> #include <vector> using namespace std; typedef long long LL; const LL mod=1000000007; const int maxn=55; LL dp[3][maxn][maxn][maxn]; int V[3]; int n; void DP() { for(int i=0; i<=V[0]; ++i) for(int j=0; j<=V[1]; ++j) { for(int k=0; k<=V[2]; ++k) { for(int l=0; l<3; ++l) { if(l==0) { dp[1][i][j+1][k]+=dp[0][i][j][k]; dp[2][i][j][k+1]+=dp[0][i][j][k]; } else if(l==1) { dp[0][i+1][j][k]+=dp[1][i][j][k]; dp[2][i][j][k+1]+=dp[1][i][j][k]; } else if(l==2) { dp[0][i+1][j][k]+=dp[2][i][j][k]; dp[1][i][j+1][k]+=dp[2][i][j][k]; } dp[0][i+1][j][k]%=mod; dp[1][i][j+1][k]%=mod; dp[2][i][j][k+1]%=mod; }//for l }//for l }//for k } LL solve() { LL ans=0; memset(dp,0,sizeof(dp)); dp[0][1][0][0]=0; dp[1][0][1][0]=(V[1]>=1)?1:0; dp[2][0][0][1]=(V[2]>=1)?1:0; DP(); ans+=dp[0][V[0]][V[1]][V[2]]; ans%=mod; memset(dp,0,sizeof(dp)); dp[0][1][0][0]=(V[0]>=1)?1:0; dp[1][0][1][0]=0; dp[2][0][0][1]=(V[2]>=1)?1:0; DP(); ans+=dp[1][V[0]][V[1]][V[2]]; ans%=mod; memset(dp,0,sizeof(dp)); dp[0][1][0][0]=(V[0]>=1)?1:0; dp[1][0][1][0]=(V[1]>=1)?1:0; dp[2][0][0][1]=0; DP(); ans+=dp[2][V[0]][V[1]][V[2]]; ans%=mod; return ans; } int main() { int T; cin>>T; while(T--) { memset(V,0,sizeof(V)); char s[300]; cin>>s; n=strlen(s); for(int i=0; s[i]; ++i) V[s[i]-‘A‘]++; cout<<solve()<<endl; } return 0; }
第二天ygp学长的代码,打表速度很快,10ms。五位数组差点把我绕进去,但是最后一维表示末尾珠子的确很神奇。
表示看懂都花了好久>_<
其实这道题已经不是dp,是递推。
f[s][i][j][k][l] s是起始珠子,i,j,k分别表示a,b,c珠子的数量,l表示末尾珠子
#include <iostream> #include <cstdio> #include <cstring> #define AC 1000000007 static int f[3][100][100][100][3]; static int color[3]; static char string0[10000]; static int i,j,k,l,h,s; using namespace std; int dp() { memset(f,0,sizeof(f)); for(s=0;s<3;s++)//s起始珠子 { if(s==0) f[0][1][0][0][0]=1; if(s==1) f[1][0][1][0][1]=1; if(s==2) f[2][0][0][1][2]=1; for(h=2;h<=70;h++)//因为是打表,所以遍历每一种长度 for(i=0;i<=h;i++)//遍历每一种a珠子的数目 for(j=0;j<=h-i;j++)//遍历每一种b珠子的数目 { k=h-i-j;//遍历每一种c珠子的数目 for(l=0;l<3;l++)//末尾珠子 { if((l==0)&&(i>0)) f[s][i][j][k][l]=(f[s][i-1][j][k][1]%AC+f[s][i-1][j][k][2]%AC)%AC; if((l==1)&&(j>0)) f[s][i][j][k][l]=(f[s][i][j-1][k][0]%AC+f[s][i][j-1][k][2]%AC)%AC; if((l==2)&&(k>0)) f[s][i][j][k][l]=(f[s][i][j][k-1][0]%AC+f[s][i][j][k-1][1]%AC)%AC; } } } return 0; } int main() { int t,sum; dp(); while(scanf("%d",&t)!=EOF) while(t--) { scanf("%s",string0); l=strlen(string0); memset(color,0,sizeof(color)); //cout<<string0<<endl; for(i=0;i<l;i++) color[string0[i]-‘A‘]++; sum=0; for(k=0;k<3;k++) if (color[k]!=0) for(l=0;l<3;l++) if(k!=l) sum=(sum+f[k][color[0]][color[1]][color[2]][l])%AC; printf("%d\n",sum%AC); } }
YGP
时间: 2024-12-21 22:58:24