3 ABAB ABABA ABABABABABABABABABABABABABABABABABABABABABABABABAB
2 0 2
这几天一直在看区间dp,下意识的相用区间dp做发现不可行,搜了半天才看到一个题解说是用4维dp做
以前没接触过也就想不到用dp【i,a,b,j】来表示第i个小朋友,之前已经吃了a个A蛋糕和b个B蛋糕现在吃第j种蛋糕的方案数(j=1,2,3)(a+b+c=i)
然后枚举第一次吃A OR B OR C蛋糕的情况 然后就是细节问题了
ACcode:
#include <map> #include <queue> #include <cmath> #include <cstdio> #include <cstring> #include <stdlib.h> #include <iostream> #include <algorithm> #define maxn 55 #define mod 1000000007 #define inf 0x3f3f3f using namespace std; /** 所有数据不超过50蛋糕只有3种,4维dp可以搞,枚举A,B吃了多少个, 再枚举这个人吃什么,按照人数从1推到n就可以了,由于人是成环形, 还要注意第n个和第1个人不吃相同的。所以根据第1个人吃什么, 做3遍上述的dp,统计答案就行。 **/ char s[maxn]; int dp[maxn][maxn][maxn][4];///dp[i,a,b,j]到第i个人时候吃了a个蛋糕A蛋糕b个B蛋糕次到j类蛋糕 int num[4],na,nb,nc;///记录每种蛋糕的个数 long long ans;///答案 int main(){ int t; scanf("%d",&t); while(t--){ ans=0; scanf("%s",s+1); int len=strlen(s+1); memset(num,0,sizeof(num)); na=num[1]=count(s+1,s+1+len,'A'); nb=num[2]=count(s+1,s+1+len,'B'); nc=num[3]=count(s+1,s+1+len,'C'); for(int loop=1;loop<=3;++loop){ if(num[loop]){ ///下面是第一个吃A,B,C蛋糕的初始化 memset(dp,0,sizeof(dp)); if(loop==1)dp[1][1][0][1]=1; else if(loop==2)dp[1][0][1][2]=1; else dp[1][0][0][3]=1; for(int i=2;i<=len;++i) for(int a=0;a<=min(i,na);++a) for(int b=0;b<=min(i-a,nb);++b){ int c=i-a-b; if(a&&((i!=2&&i!=len)||loop!=1))///第i个小朋友吃A蛋糕的情况 dp[i][a][b][1]=(dp[i][a][b][1]+dp[i-1][a-1][b][2]+dp[i-1][a-1][b][3])%mod; if(b&&((i!=2&&i!=len)||loop!=2))///第i个小朋友吃B蛋糕的情况 dp[i][a][b][2]=(dp[i][a][b][2]+dp[i-1][a][b-1][1]+dp[i-1][a][b-1][3])%mod; if(c&&((i!=2&&i!=len)||loop!=3))///第i个小朋友吃C蛋糕的情况 dp[i][a][b][3]=(dp[i][a][b][3]+dp[i-1][a][b][1]+dp[i-1][a][b][2])%mod; } long long tmp; tmp=(dp[len][na][nb][1]+dp[len][na][nb][2]+dp[len][na][nb][3])%mod; ans=(ans+tmp)%mod; } } printf("%lld\n",ans); } return 0; }