|NOIP提高2015(部分)

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

猜你喜欢

转载自blog.csdn.net/qq_35923186/article/details/82707949