• 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;
    }
    
  • 相关阅读:
    MVC vs SVC
    迪米特原则与接口隔离原则
    依赖倒置原理:依赖、稳定的抽象层
    【调侃】IOC前世今生
    Visual SVN Server启动失败0x8007042a错误
    syntax error, unexpected '['
    navicat将多个表导出为一个sql文件
    我的flashfxp左右界面怎么变成这样了?
    什么是国际顶级域名?
    什么是A记录/CNAME记录/MX记录/TXT记录
  • 原文地址:https://www.cnblogs.com/chdy/p/12717344.html
Copyright © 2020-2023  润新知