CodeForces 360 C.Levko and Strings(组合数学+dp)

202 篇文章 1 订阅
190 篇文章 1 订阅

Description

给出一个长度为 n 的只由小写字母组成的字符串,定义另一个长度为n的只由小写字母组成的字符串 t s的相关度为二元组 (i,j) 的对数,其中 i,j 需满足 1ijn,t[i,...,j] 字典序大于 s[i,...,j] ,问和 s 相关度为k的字符串 t 的个数

Input

第一行两个整数n,k表示字符串长度和相关度,之后输入一个长度为 n ,只由小写字母组成的字符串s (1n2000,0k2000)

Output

输出和 s 相关度为k的字符串个数,结果模 109+7

Sample Input

2 2
yz

Sample Output

26

Solution

dp[i][j] 表示 t 的前i个字符已经放好,后面的字符和 s 相同且产生了j个相关度的方案数

假设 s t在第 i 个位置之前第一个不同的位置在l,即 s[l+1,...,i1]=t[l+1,...,i1] ,那么当第 i 个位置t[i]取的比 s[i] 大时,起点在 [l+1,i] 之间,终点在 [i,n] 之间的区间都会产生一个相关度,而对于起点在 [1,l] 之间,终点在 [l+1,n] 之间的区间, s t不同的位置必然在 l+1 之前,第 i 个位置怎么填不会影响其对相关度的贡献,其相关度的贡献之前已经算过了,故有转移方程dp[i][j]+=(zs[i])l=0i1dp[il][j(il)(ni+1)];如果第 i 个位置t[i]取的比 s[i] 小时,不会产生新的相关度,故有 dp[i][j]+=(s[i]a)l=0i1dp[l][j] ,用 sum[j] 维护 l=0i1dp[l][j] ,则这块 O(1) 转移,最后 i=0ndp[i][k] 即为答案

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=2005;
#define mod 1000000007
int n,k,dp[maxn][maxn],sum[maxn];
char s[maxn];
void add(int &x,int y)
{
    x=x+y>=mod?x+y-mod:x+y;
}
int Solve()
{
    sum[0]=dp[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=k;j++)
        {
            for(int l=i-1;l>=0&&(i-l)*(n-i+1)<=j;l--)
                add(dp[i][j],dp[l][j-(i-l)*(n-i+1)]);
            dp[i][j]=(ll)('z'-s[i])*dp[i][j]%mod;
            add(dp[i][j],(ll)(s[i]-'a')*sum[j]%mod);
            add(sum[j],dp[i][j]);
        }
    }
    int ans=0;
    for(int i=0;i<=n;i++)add(ans,dp[i][k]); 
    return ans;
}
int main()
{
    scanf("%d%d",&n,&k);
    scanf("%s",s+1);
    printf("%d\n",Solve());
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值