NOIP提高组2015
神奇的幻方
模拟完事
信息传递
发现图是一个基环树 拓扑排序然后把环找出来就行了
跳石头
二分答案On判断
子串
可以记dp[0/1][j][x]表示这一位置上选或没选 共匹配到第j个位置 分成了x段, 考虑转移
dp[0][j][x]=dp[1][j][x]+dp[0][j][x];
dp[1][j][x]=dp[0][j-1][x-1]+dp[1][j-1][x];
显然每种方案选的位置各不相同 更新答案
对于每一个x我们已经将它分为x段 再分出k-x段就行了 而还可以再分割的位置有m-1-(x-1)=m-x个 我们需要从中选出k-x个位置
所以ans+=(dp[0][m][x]+dp[1][m][x])*c[m-x][k-x];
- 代码
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
char a[2010],b[1010];
int mod=1e9+7;
int dp[3][2][210][210];
int c[210][210];
int main()
{
int now=0,pre=1;
scanf("%d%d%d",&n,&m,&k);
scanf("%s",a+1);
scanf("%s",b+1);
dp[pre][0][0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++)
for(int x=0;x<=k;x++)
dp[now][0][j][x]=(dp[pre][1][j][x]+dp[pre][0][j][x])%mod;
for(int j=0;j<=m;j++)
for(int x=0;x<=k;x++)
dp[now][1][j][x]=0;
for(int j=1;j<=m;j++)if(a[i]==b[j])
{
for(int x=0;x<=k;x++){
dp[now][1][j][x]+=dp[pre][1][j-1][x];
if(x>0)dp[now][1][j][x]+=dp[pre][0][j-1][x-1];
dp[now][1][j][x]%=mod;
}
}
swap(now,pre);
}
c[0][0]=1;
for(int i=1;i<=m;i++)
c[i][0]=c[i][i]=1;
for(int i=1;i<=m;i++)
for(int j=1;j<=i-1;j++){
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
long long ans=0;
for(int i=1;i<=k;i++){
long long pp=dp[pre][0][m][i]+dp[pre][1][m][i];
ans+=pp*c[m-i][k-i];
ans%=mod;
}
printf("%lld\n",ans);
}