• [NOI2009]管道取珠


    [NOI2009]管道取珠

    给出一个长度为n的01序列({a_i})和一个长度为m的01序列({b_i}),给出(n+m)个格子,按顺序将a和b填入,也就是事先选好n个位置,按顺序地填入a,然后其它的按顺序填入b,设填后的格子有(c)次重复,问所有的格子填法(c^2)的和,(n,mleq 500)

    平方可以转换为两个人填,方案相同的方案数,于是设(f[i][j][k])表示两个人都填到了第i个个子,两人分别填到a序列中的第j个位置第k个位置的方案相同的方案数。

    显然可以得知它们分别填到b序列的第(i-j,i-k)个位置,于是有

    [f[i][j][k]=egin{cases}f[i-1][j-1][k-1](a[j]==a[k])\f[i-1][j-1][k](a[j]==b[i-k])\f[i-1][j][k-1](b[i-j]==a[k])\f[i-1][j][k](b[i-j]==b[i-k])end{cases} ]

    显然边界为(f[0][0][0]=1),答案是(f[n+m][n][m])

    参考代码:

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    #define Size 550
    #define gzy 1024523
    using namespace std;
    bool a[Size],b[Size];
    int dp[Size][Size];
    il void get(char&);
    int main(){
    	char c;int n,m;scanf("%d%d",&n,&m);
    	for(ri int i(1);i<=n;++i)get(c),a[i]=c=='A';
    	for(ri int i(1);i<=m;++i)get(c),b[i]=c=='A';
    	dp[0][0]=1;
    	for(ri int i(1),j,k;i<=n+m;++i)
    		for(j=min(i,n);j>=0;--j)
    			for(k=min(i,n);k>=0;--k){
    				if(!(i-j)||!(i-k)||b[i-j]!=b[i-k])dp[j][k]=0;
    				if(k&&j&&a[j]==a[k])dp[j][k]+=dp[j-1][k-1];
    				if(j&&a[j]==b[i-k]&&i-k)dp[j][k]+=dp[j-1][k];
    				if(k&&b[i-j]==a[k]&&i-j)dp[j][k]+=dp[j][k-1];
    				dp[j][k]%=gzy;
    			}printf("%d",dp[n][n]);
    	return 0;
    }
    il void get(char &c){
    	while(c=getchar(),c==' '||c=='
    '||c=='
    ');
    }
    
    
  • 相关阅读:
    C语言I博客作业04
    C语言I博客作业03
    C语言1博客作业02
    作业1
    C语言||作业01
    C语言寒假大作战04
    C语言寒假大作战03
    C语言寒假大作战02
    C语言寒假大作战01
    笔记本
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11429119.html
Copyright © 2020-2023  润新知