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

题目描述
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 1000000007
using 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值