zoukankan      html  css  js  c++  java
  • CF R 635 div1 C Kaavi and Magic Spell 区间dp

    LINK:Kaavi and Magic Spell

    一打CF才知道自己原来这么菜 这题完全没想到.

    可以发现 如果dp f[i][j]表示前i个字符匹配T的前j个字符的方案数 此时转移变得异常麻烦 状态转移一次变成了O(n).

    会超时 而且这个状态的转移也是不正确的 可能当前的S字符串后面放了一些不能匹配的东西 但是此时却体现不出来.

    那我们如何描述每次增加一个字符且和T匹配多少这种状态呢.

    一个思路 先对于S串的某个i暴力枚举 其对应在T中的位置 这样的话dp就变成了

    f[i][j][k]表示前i个字符 匹配了T中j~k区间的方案数 这样就没有刚才的问题了。

    不过 这个状态还是不行 因为存在重复 的方案被统计到了.

    仔细思考 对于刚才的那个状态 之所以会重复是因为两种方案的重叠都被我们枚举到了。

    考虑最终的答案的方案数 不难发现对于i号点来说 其位置是不固定的。

    我们完全可以只枚举1的位置在哪然后进行上述的区间dp.

    这样的话就既没有加到队首 整体右移的问题 也没有状态数重复的问题.

    有状态 f[i][j]表示 前j-i+1个字符 匹配了T的 i~j的区间的方案数.

    考虑转移.

    对于 第j-i+2个字符 可以判断一下能否转移即可。

    由于每次使用的字符固定 不需要再枚举决策。

    所以复杂度为n^2.

    const int MAXN=3010;
    int T,n,ans,m;
    int f[MAXN][MAXN];
    char a[MAXN],b[MAXN];
    int main()
    {
    	freopen("1.in","r",stdin);
    	gc(a);gc(b);
    	n=strlen(a+1);
    	m=strlen(b+1);
    	rep(1,n,i)if(a[1]==b[i]||i>m)f[i][i]=1;
    	for(int len=2;len<=n;++len)
    	{
    		for(int i=1;i<=n-len+1;++i)
    		{
    			int j=i+len-1;
    			if(a[len]==b[i]||i>m)f[i][j]=(f[i][j]+f[i+1][j])%mod;
    			if(a[len]==b[j]||j>m)f[i][j]=(f[i][j]+f[i][j-1])%mod;
    		}
    	}
    	rep(m,n,i)ans=(ans+f[1][i])%mod;
    	put(ans*2%mod);
    	return 0;
    }
    
  • 相关阅读:
    无限维
    黎曼流形
    why we need virtual key word
    TOJ 4119 Split Equally
    TOJ 4003 Next Permutation
    TOJ 4002 Palindrome Generator
    TOJ 2749 Absent Substrings
    TOJ 2641 Gene
    TOJ 2861 Octal Fractions
    TOJ 4394 Rebuild Road
  • 原文地址:https://www.cnblogs.com/chdy/p/12717344.html
Copyright © 2011-2022 走看看