CodeForces - 361E Levko and Strings
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
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
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
Output
Print a single number — the answer to the problem modulo 1000000007 (109?+?7).
Examples
Input2 2Output
yz
26
Input
2 3Output
yx
2
Input
4 7Output
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