Codeforces 176B【计数DP】

题意:

给你两个串s1,s2和一个K,
有一种操作是在一个串切开然后交换位置,
问s1有多少种方法经过K次这样的操作变成s2;

思路:

(从来没接触过计数DP...还是太菜...参考了【大牛blog

首先呢,不管怎么切怎么换,都是原串自己转来转去有没有???看到这个其实我还是不懂。。。。

然后呢,我们搞一个DP数组记下数,纯粹就是计数的;


dp[now][0]代表到第i步变成原串的方案数;

dp[now][1]代表到第i步变成非原串的方案数;

从哪里变成原串啊?一个原串可以变成len-1个非原串,那么len-1个非原串也能变成1个原串咯

从哪里变成非原串?本来原串能变成len-1个非原串,而每个非原串又能变成1个原串,还能变成len-2个跟他也不同的串;

so...

dp[now][0]=dp[last][1]*(len-1);

dp[now][1]=dp[last][0]+dp[last][1]*(len-2);

最后只要枚举一下环,有没有哪个位置开始起和目标串一样,然后加上方案就好了;

牛逼啊;

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const double eps=1e-5;
const double pi=acos(-1.0);
const int INF=0x3f3f3f3f;

const int mod=1e9+7;
const int N=1e3+10;
char s1[N],s2[N];
int k;

LL dp[2][2];

int main()
{
    int len;
    scanf("%s%s%d",s1,s2,&k);
    len=strlen(s1);
    for(int i=0;i<len;i++)
        s1[i+len]=s1[i];

    int now=0;
    dp[now][0]=1;
    dp[now][1]=0;

    for(int i=1;i<=k;i++)
    {
        now=1-now;
        dp[now][0]=(len-1)*dp[1-now][1]%mod;
        dp[now][1]=(dp[1-now][0]+dp[1-now][1]*(len-2)%mod)%mod;
    }

   //printf("%lld %lld\n",dp[now][0],dp[now][1]);

    LL ans=0;
    for(int i=0;i<len;i++)
    {
        int pos=i;
        for(int j=0,t=i;j<len;t++,j++)
        {
            if(s1[t]!=s2[j])
            {
                pos=-1;
                break;
            }
        }
        if(pos!=-1)
        {
            if(pos==0)
                ans=(ans+dp[now][0])%mod;
            else
                ans=(ans+dp[now][1])%mod;
        }
    }
    printf("%lld\n",ans);
    return 0;
}





posted @ 2016-12-05 20:39  see_you_later  阅读(218)  评论(0编辑  收藏  举报