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; }