码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-05-04 23:35:08      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:

第五届省赛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;
}
 
View Code

 

技术分享
#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;
}
View Code

 

第二天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

 

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

标签:

原文地址:http://www.cnblogs.com/travelller/p/4477693.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!