[sdut]2879计数dp……或者递推

第五届省赛C:colourful cupcakes

N=60.

天真如我,居然在考虑搜索的算法/(ㄒoㄒ)/~~三叉树……3^60=10^24+……不计算考虑复杂度都是耍流氓>_<

再算了一下,感觉O(N^4)可以试试,60^4=10^8+……但是毕竟最差的情况嘛>_<,再看一下题解果然是4重循环的……计数……dp……(想到之前坚信的搜索不禁(*/ω\*))

中间看到了一个三次动规六个方程的算法。

做麻烦了。

学长思路好快。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<vector>

using namespace std;

#define clr(c,x) memset(c,x,sizeof(c));
#define rep(i,f,t) for(int i = (f), _end = (t); i <= _end; ++i)
#define debug(x) cout<<"debug  "<<x<<endl;
typedef long long int64;
const int mod = 1000000007;
int n,A,B,C;
char str[55];
int cnt[3];
int64 d[55][55][55][3];

int solve(int x){ //表示固定第一块蛋糕为x类的方案数。
    clr(d,0);
    if(x==0) d[1][1][0][0] = 1;
    else if(x == 1) d[1][0][1][1] = 1;
    else d[1][0][0][2] = 1;

    rep(i,2,n)rep(a,0,min(i,A))rep(b,0,min(B,i-a)){
        int c = i-a-b;
        if(c > C)continue;
        if( (a==0)+(b==0)+(c==0) >= 2)continue;  //abc出现两个以上的0为无效状态

        if(a && ((i!=2 && i!=n) || x!=0))d[i][a][b][0] = ( d[i][a][b][0] + d[i-1][a-1][b][1] + d[i-1][a-1][b][2] ) % mod;
        if(b && ((i!=2 && i!=n) || x!=1))d[i][a][b][1] = ( d[i][a][b][1] + d[i-1][a][b-1][0] + d[i-1][a][b-1][2] ) % mod;
        if(c && ((i!=2 && i!=n) || x!=2))d[i][a][b][2] = ( d[i][a][b][2] + d[i-1][a][b][0] + d[i-1][a][b][1] ) % mod;
    }
    return ( d[n][A][B][0] + d[n][A][B][1] + d[n][A][B][2] ) % mod;
}
int main(){
    int casn;
    scanf("%d",&casn);
    while(casn--){
        scanf("%s",str);
        n = strlen(str);
        A = cnt[0] = count(str,str+n,‘A‘);
        B = cnt[1] = count(str,str+n,‘B‘);
        C = cnt[2] = count(str,str+n,‘C‘);
        int64 ans[3];clr(ans,0);
        rep(i,0,3)if(cnt[i])ans[i] = solve(i);
        ans[0] += ans[1]+ans[2];
        ans[0] %= mod;
        printf("%d\n",ans[0]);
    }
    return 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;
                }//for l
            }//for l
        }//for k
}
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;
}

第二天ygp学长的代码,打表速度很快,10ms。五位数组差点把我绕进去,但是最后一维表示末尾珠子的确很神奇。

表示看懂都花了好久>_<

其实这道题已经不是dp,是递推。

f[s][i][j][k][l] s是起始珠子,i,j,k分别表示a,b,c珠子的数量,l表示末尾珠子

#include <iostream>
#include <cstdio>
#include <cstring>
#define AC 1000000007
static int f[3][100][100][100][3];
static int color[3];
static char string0[10000];
static int i,j,k,l,h,s;
using namespace std;
int dp()
{
    memset(f,0,sizeof(f));
    for(s=0;s<3;s++)//s起始珠子
    {
        if(s==0) f[0][1][0][0][0]=1;
        if(s==1) f[1][0][1][0][1]=1;
        if(s==2) f[2][0][0][1][2]=1;
        for(h=2;h<=70;h++)//因为是打表,所以遍历每一种长度
            for(i=0;i<=h;i++)//遍历每一种a珠子的数目
                for(j=0;j<=h-i;j++)//遍历每一种b珠子的数目
                {
                    k=h-i-j;//遍历每一种c珠子的数目
                    for(l=0;l<3;l++)//末尾珠子
                    {
                        if((l==0)&&(i>0)) f[s][i][j][k][l]=(f[s][i-1][j][k][1]%AC+f[s][i-1][j][k][2]%AC)%AC;
                        if((l==1)&&(j>0)) f[s][i][j][k][l]=(f[s][i][j-1][k][0]%AC+f[s][i][j-1][k][2]%AC)%AC;
                        if((l==2)&&(k>0)) f[s][i][j][k][l]=(f[s][i][j][k-1][0]%AC+f[s][i][j][k-1][1]%AC)%AC;
                    }
                }
    }
    return 0;
}
int main()
{
    int t,sum;
    dp();
    while(scanf("%d",&t)!=EOF)
    while(t--)
    {
        scanf("%s",string0);
        l=strlen(string0);
        memset(color,0,sizeof(color));
        //cout<<string0<<endl;
        for(i=0;i<l;i++)
            color[string0[i]-‘A‘]++;
        sum=0;
        for(k=0;k<3;k++)
            if (color[k]!=0)
                for(l=0;l<3;l++)
                    if(k!=l) sum=(sum+f[k][color[0]][color[1]][color[2]][l])%AC;
        printf("%d\n",sum%AC);
    }
}

YGP

时间: 2024-12-21 22:58:24

[sdut]2879计数dp……或者递推的相关文章

[ACM] hdu 3853 LOOPS (概率DP,递推)

LOOPS Problem Description Akemi Homura is a Mahou Shoujo (Puella Magi/Magical Girl). Homura wants to help her friend Madoka save the world. But because of the plot of the Boss Incubator, she is trapped in a labyrinth called LOOPS. The planform of the

timus 1225 flags 基础DP 简单递推

1225. Flags Time limit: 1.0 secondMemory limit: 64 MB On the Day of the Flag of Russia a shop-owner decided to decorate the show-window of his shop with textile stripes of white, blue and red colors. He wants to satisfy the following conditions: Stri

HDU 3899 树形DP||树上递推

JLUCPC 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3899 Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1375    Accepted Submission(s): 413 Problem Description Dr. Skywind and Dr. Walkonclo

UESTC 2016 Summer Training #2 Div.2 A dp、递推、多阶段问题

A - A Time Limit:336MS     Memory Limit:1572864KB     64bit IO Format:%lld & %llu Submit Status Practice SPOJ AMR11A Description Thanks a lot for helping Harry Potter in finding the Sorcerer's Stone of Immortality in October. Did we not tell you that

UVa 825【简单dp,递推】

UVa 825 题意:给定一个网格图(街道图),其中有一些交叉路口点不能走.问从西北角走到东南角最短走法有多少种.(好像没看到给数据范围...) 简单的递推吧,当然也就是最简单的动归了.显然最短路长度就是row+col.求种数就从开始往后推. 由于第一行第一列也有可能是障碍点,所以初始化时要注意这一点,或者干脆就只初始化f[0][1]=1.i.j都从1开始递推到更方便.还有题目输入输出比较坑.输入我用的是sstream和stream,方便很多,要不还要按照字符串输入再手动转化成数字.输出让每组隔

数的计数(noip2001,动态规划递推)

题目链接: 普通版: https://www.luogu.org/problemnew/show/P1028 数据加强版: https://www.luogu.org/problemnew/show/P2240 中间插一段,奇怪了,我明明想到的是最好的那种递推方法,结果写着写着忘记了,写成最差的递推方法 所以中间插一段被我遗忘的好方法 这个也是这题的书上的答案 #include<bits/stdc++.h> using namespace std; int a[1001]; int main(

钥匙计数之一(递推)hdu1438

钥匙计数之一 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1471    Accepted Submission(s): 622 Problem Description 一把锁匙有N个槽,槽深为1,2,3,4.每锁匙至少有3个不同的深度且至少有1对相连的槽其深度之差为3.求这样的锁匙的总数. Input 本题无输入 Output 对

HDU 2045不容易系列之三LELE的RPG难题(趋向于DP的递推)

不容易系列之(3)-- LELE的RPG难题 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 30222 Accepted Submission(s): 12144 Problem Description 人称"AC女之杀手"的超级偶像LELE最近忽然玩起了深沉,这可急坏了众多"Cole"(LELE的粉丝,即&q

51nod 1020 逆序排列(dp,递推)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1020 题意:是中文题. 题解:很显然要设dp[i][j]表示,i个数有j个逆序对有几种然后就是状态的转移, dp[i][j]=dp[i-1][max(0,j-(i-1)]+.....+dp[i-1][max(j,(i-1)*(i-2)/2]; 还会用到前缀和,还有注意最后结果加mod再膜mod,结果可能会负数. #include <iostream> #i