标签:codeforce ret answer single class 整点数 english air substring
Discription
Levko loves strings of length n, consisting of lowercase English letters, very much. He has one such string s. For each string t of length n, Levko defines its beauty relative to s as the number of pairs of indexes i, j (1?≤?i?≤?j?≤?n), such that substring t[i..j] is lexicographically larger than substring s[i..j].
The boy wondered how many strings t are there, such that their beauty relative to sequals exactly k. Help him, find the remainder after division this number by1000000007 (109?+?7).
A substring s[i..j] of string s?=?s1s2... sn is string sisi??+??1... sj.
String x??=??x1x2... xp is lexicographically larger than string y??=??y1y2... yp, if there is such number r (r?<?p), that x1??=??y1,??x2??=??y2,??... ,??xr??=??yr and xr??+??1?>?yr??+??1. The string characters are compared by their ASCII codes.
Input
The first line contains two integers n and k (1?≤?n?≤?2000, 0?≤?k?≤?2000).
The second line contains a non-empty string s of length n. String s consists only of lowercase English letters.
Output
Print a single number — the answer to the problem modulo 1000000007 (109?+?7).
Examples
2 2
yz
26
2 3
yx
2
4 7
abcd
21962
不难想到设状态 f[i][j] 表示:已经考虑了第i位往后的字符,并且此时有j对 T 字典序严格大于 S的区间的方案数。
根据设定的状态,我们可以直接得出一个 O(N^3) 的转移:
当我们要计算 f[i][?] 的时候,我们先枚举第二维是多少,然后再枚举T[i~n]与S[i~n]第一个不一样的字符对 T[k]&&S[k] 在哪里,然后算贡献。
也就是 f[i][j] = ∑ (s[k] - 1) * f[k+1][j] + ∑ (26 - s[k]) * f[k+1][j- (n-k+1) * (k-i+1)]. (i<=k<=n)
现在来考虑一下怎么优化这个dp。
第一个∑比较好优化,直接用一个 g[j] 记录 (s[k] - 1) * f[k+1][j] 这个后缀和就好了。
第二个∑看起来好复杂啊。。。。这该咋优化。
考虑我们枚举i的时候,i和n都是固定的,所以 (n-k+1) * (k-i+1) 此时就是一个关于 k 的开口向下的二次函数,发现k靠近i或者靠近n的时候,这个函数值不是很大,而当k趋近于 (n+i)/2 的时候,这个函数值很大,很可能没法转移。
这告诉我们什么?
第二种转移的实际路径其实特别少,并且都是 一个 前缀 + 一个 后缀 (对于k来说)的形式,所以我们只需要当j增加的时候记录 前缀右端点 和 后缀左端点的移动,然后直接暴力转移即可。
那么怎么证明这个函数的转移路径真的很少呢?
我们来列一下式子,实际的转移路径总数 = ∑ ∑ ∑ [(n+2-i-j)*j <= k]
可以抽象成 二次函数 y=x(1-x) ,y=x(2-x) ...,y=x(n+2-x) 在 y=1,y=2....y=k直线 下的整点数量和,可以发现的确是很少的hhhh(谁让我也不会具体证明啦)
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=2005,ha=1e9+7; inline void add(int &x,int y){ x+=y; if(x>=ha) x-=ha;} inline int ADD(int x,int y){ x+=y; return x>=ha?x-ha:x;} int f[maxn][maxn],n,m,g[maxn],k,ans=0; char s[maxn]; inline void solve(){ f[n+1][0]=1; for(int i=n;i;i--){ for(int j=0;j<=k;j++) add(g[j],f[i+1][j]*(ll)(s[i]-‘a‘)%ha); int L=i-1,R=n+1; for(int j=0;j<=k;j++){ while(j>=(n-L)*(L+2-i)&&L+1<R) L++; while(j>=(n-R+2)*(R-i)&&L+1<R) R--; for(int l=i;l<=L;l++) add(f[i][j],(‘z‘-s[l])*(ll)f[l+1][j-(n-l+1)*(l-i+1)]%ha); for(int l=n;l>=R;l--) add(f[i][j],(‘z‘-s[l])*(ll)f[l+1][j-(n-l+1)*(l-i+1)]%ha); add(f[i][j],g[j]); } add(f[i][0],1); } } int main(){ scanf("%d%d",&n,&k); scanf("%s",s+1); solve(); printf("%d\n",f[1][k]); return 0; }
CodeForces - 361E Levko and Strings
标签:codeforce ret answer single class 整点数 english air substring
原文地址:https://www.cnblogs.com/JYYHH/p/8984831.html