山东省第五届ACM省赛题——Colorful Cupcakes(四维dp)

来源:互联网 发布:metrics java 编辑:程序博客网 时间:2024/06/05 06:11

题目描述
Beaver Bindu has N cupcakes. Each cupcake has one of three possible colors. In this problem we will represent the colors by uppercase letters \’A\’, \’B\’, and \’C\’. Two cupcakes of the same color are indistinguishable. You are given a String cupcakes consisting of exactly N characters. Each character in cupcakes gives the color of one of Bindu\’s cupcakes.

Bindu has N friends, sitting around a round table. She wants to give each friend one of the cupcakes. Moreover, she does not want to give cupcakes of the same color to any pair of friends who sit next to each other.

Let X be the number of ways in which she can hand out the cupcakes to her friends. As X can be very large, compute and return the value (X modulo 1, 000, 000, 007).
输入
The first line contains one integer T(1 ≤ T ≤ 60)—the number of test cases. Each of the next T lines contains one string. Each string will contain between 3 and 50 characters, inclusive. Each character in the string will be either \’A\’, \’B\’, or \’C\’.
输出
For each test case. Print a single number X — the number of ways in which she can hand out the cupcakes to her friends.

示例输入
3
ABAB
ABABA
ABABABABABABABABABABABABABABABABABABABABABABABABAB
示例输出
2
0
2

目前只找到一种用四维dp的方法,dp[i][a][b][j]表示第i个人吃了第j中蛋糕,已经用去了a块A蛋糕,b块B蛋糕。具体的步骤看注释就懂了

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <vector>#include <queue>#include <set>#define MAXN 55#define mod 1000000007using namespace std;long long min(long long a,long long b){    if(a>b)        return b;    else        return a;}long long dp[MAXN][MAXN][MAXN][4];  //dp[i][a][b][j],第i个人吃了第j种蛋糕,已经用去了a个A蛋糕和b个B蛋糕int num[3];  //num表示每种蛋糕的个数long long ans;char s[MAXN];int main(){    int t,n;    scanf("%d",&t);    while(t--)    {        scanf("%s",s+1);        n=strlen(s+1);        num[0]=count(s+1,s+1+n,'A');        num[1]=count(s+1,s+1+n,'B');        num[2]=count(s+1,s+1+n,'C');        ans=0;        for(int i=0; i<3; ++i)  //分别对第一个人吃的蛋糕种类进行枚举        {            if(num[i])            {                memset(dp,0,sizeof(dp));  //因为是枚举第一个人吃的,要分三种情况,因此每次要初始化                if(i==0)                    dp[1][1][0][0]=1;  //如果第一个人吃的是A蛋糕                if(i==1)                    dp[1][0][1][1]=1;  //第一个人吃B蛋糕                if(i==2)                    dp[1][0][0][2]=1;  //第一个人吃C蛋糕                //接下来对剩下的n-1个人求解                for(int p=2; p<=n; ++p)  //p表示当前吃蛋糕的人                    for(int a=0; a<=min(p,num[0]); ++a)  //a表示用了a块A蛋糕,第p个人吃的时候,A蛋糕不确定有没有吃完                        for(int b=0; b<=min(p-a,num[1]); ++b)  //用了b块B蛋糕                        {                            int c=p-a-b;                            if(a&&(p!=2&&p!=n)||i!=0)  //第i个人吃了A蛋糕,那么第一个人就不能吃(i!=0),除非这个人不是第二个或最后一个(p!=2||p!=0)                                dp[p][a][b][0]=(dp[p][a][b][0]+dp[p-1][a-1][b][1]+dp[p-1][a-1][b][2])%mod;                            if(b&&(p!=2&&p!=n)||i!=1)                                dp[p][a][b][1]=(dp[p-1][a][b-1][0]+dp[p][a][b][1]+dp[p-1][a][b-1][2])%mod;                            if(c&&(p!=2&&p!=n)||i!=2)                                dp[p][a][b][2]=(dp[p-1][a][b][0]+dp[p-1][a][b][1]+dp[p][a][b][2])%mod;                        }                ans=(ans+dp[n][num[0]][num[1]][0]+dp[n][num[0]][num[1]][1]+dp[n][num[0]][num[1]][2])%mod;            }        }        printf("%lld\n",ans);    }    return 0;}
0 0
原创粉丝点击