1. 程式人生 > >CodeForces - 361E Levko and Strings

CodeForces - 361E Levko and Strings

substr 字符 equal con cte 現在 english ger ++

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

Input
2 2
yz
Output
26
Input
2 3
yx
Output
2
Input
4 7
abcd
Output
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