<span>SDUTOJ2879 Colorful Cupcakes(dp)</span>
山东省赛的一道题
题意:
聚会一个圆桌,相邻字母不能重复,有ABC三种字母
问有多少种方法
思路:
dp
第一维滚动,第二维ABC当前位置,后三维存ABC用的个数
由于放在了UPCOJ上,判题比较慢,优化了一下,
在SDUTIJ上20ms
/* *********************************************** Author :devil Created Time :2016/5/14 17:19:27 ************************************************ */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <stdlib.h> using namespace std; const int mod=1e9+7; int dp[2][3][27][27][27],a[3]; int main() { //freopen("in.txt","r",stdin); int t; char s[51]; scanf("%d",&t); while(t--) { scanf("%s",s); int l=strlen(s); a[0]=1,a[1]=1,a[2]=1; for(int i=0; i<l; i++) a[s[i]-'A']++; if(a[0]>a[1]) swap(a[0],a[1]); if(a[1]>a[2]) swap(a[1],a[2]); if(a[0]+a[1]<=a[2]) { printf("0\n"); continue; } l+=3; long long ans=0; for(int y=0; y<3; y++) { memset(dp,0,sizeof(dp)); if(y==0) dp[0][0][2][1][1]=1; else if(y==1) dp[0][1][1][2][1]=1; else dp[0][2][1][1][2]=1; int cur=0; for(int cnt=5; cnt<=l; cnt++) { cur^=1; for(int i=1; i<=min(a[0],cnt); i++) { for(int j=1; j<=min(a[1],cnt); j++) { int k=cnt-i-j; if(k>a[2]) continue; dp[cur][0][i][j][k]=dp[cur^1][1][i-1][j][k]+dp[cur^1][2][i-1][j][k]; if(dp[cur][0][i][j][k]>=mod) dp[cur][0][i][j][k]-=mod; dp[cur][1][i][j][k]=dp[cur^1][0][i][j-1][k]+dp[cur^1][2][i][j-1][k]; if(dp[cur][1][i][j][k]>=mod) dp[cur][1][i][j][k]-=mod; dp[cur][2][i][j][k]=dp[cur^1][1][i][j][k-1]+dp[cur^1][0][i][j][k-1]; if(dp[cur][2][i][j][k]>=mod) dp[cur][2][i][j][k]-=mod; } } } if(y==0) ans+=dp[cur][1][a[0]][a[1]][a[2]]+dp[cur][2][a[0]][a[1]][a[2]]; else if(y==1) ans+=dp[cur][0][a[0]][a[1]][a[2]]+dp[cur][2][a[0]][a[1]][a[2]]; else ans+=dp[cur][0][a[0]][a[1]][a[2]]+dp[cur][1][a[0]][a[1]][a[2]]; while(ans>=mod) ans-=mod; } printf("%lld\n",ans); } return 0; }