• Codeforces 360C DP 计算贡献


    题意:给你一个长度为n的字符串,定义两个字符串的相关度为两个串对应的子串中第一个串字典序大于第二个串的个数。现在给你相关度,和第二个串,问满足条件的第一个串有多少个?

    思路:设dp[i][j]为填了前i个字符,后面的字符和s相同,相关度为j的方案数。现在有两种转移:

    1:i位置填的字符大于s[i], 那么我们假设i前面第一个与s不相等的位置是l(即s[l + 1]到s[i]是相等的), 那么相当于左端点在[l + 1, i], 右端点在[i, n]的区间都会产生贡x献,那么从dp[l][j - (n - i + 1) * (i - l)]转移过来(把后面的贡献去掉,就是dp[l][j - (n - i + 1) * (i - l)]),dp[i][j] += ('z' - s[i]) * (dp[l][j - (n - i + 1) * (i - l)]);

    2:i位置填的数字小于等于s[i], 那么后面就没影响了,前面所有的l都可以转移:dp[i][j] += sum[j] * (s[i] - 'a), sum[j] 为dp[0][j]到dp[i - 1][j]的和。

    代码:

    #include <bits/stdc++.h>
    #define LL long long
    #define INF 0x3f3f3f3f
    #define db double
    #define pii pair<int, int>  
    using namespace std;
    const int maxn = 2010;
    const LL mod = 1000000007;
    LL dp[maxn][maxn], sum[maxn];
    char s[maxn];
    int main() {
    	int n, k;
    	scanf("%d%d", &n, &k);
    	scanf("%s", s + 1);
    	dp[0][0] = 1;
    	sum[0] = 1;
    	for (int i = 1; i <= n; i++) {
    		for (int j = 0; j <= k; j++) {
    			for (int l = i - 1; l >= 0 && j - (n - i + 1) * (i - l) >= 0; l--) {
    				dp[i][j] = (dp[i][j] + ((LL)('z' - s[i]) * dp[l][j - (n - i + 1) * (i - l)]) % mod) % mod;
    			}
    			dp[i][j] = (dp[i][j] + ((LL)(s[i] - 'a') * sum[j]) % mod) % mod;
    			sum[j] = (sum[j] + dp[i][j]) % mod;
    		}
    	}
    	LL ans = 0;
    	for (int i = 0; i <= n; i++) {
    		ans = (ans + dp[i][k]) % mod;	
    	}
    	printf("%lld
    ", ans);
    }
    

      

  • 相关阅读:
    Node_初步了解(4)小爬虫
    JS_高阶函数(map and reduce)
    tabel表格表头固定-标题固定
    js全选 不选 简单写法
    js 对象里 增加、删除一项字段 (把某对象里的数组转换为字符串,重组为新对象)
    手机号验证等汇总
    jq清除该站点的所有cookie
    ajax传参多个冒号 :
    [Vue warn]: Duplicate keys detected: ''. This may cause an update error.
    js的小数位数和保留小数点四位数字等验证
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/11123937.html
Copyright © 2020-2023  润新知