题意:给3种颜色的珠子围成一个环,要求相邻两个珠子的颜色不同,问一共有多少种情况。
思路:背包计数问题。可先将环看作一个链,dp[i][j][k][l],i表示以第i种颜色为尾,j、k、l分别表示三种颜色的珠子有多少个。如果是链的话很容易建立状态转移方程。环的话要考虑首尾位置,实际上就是对于答案dp[0][v0][v1][v2]这种,要减掉所有以第0种颜色开头的情况,所以只需要将dp[0][1][0][0]这个状态初始化为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;
}
}
}
}
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;
}