http://codeforces.com/contest/360/problem/C
極好的一道動態規劃, 給定一個小寫字母的字符串 S, 求其相同長度的串T,T中恰包含K個子串字典序大於S中相同位置的子串,求T有幾種,記 DP[ i ] [ j ][ 0或1 ] 爲 第i個位置爲止已有J個子串字典序大於S中相對應爲止的子串,最後一維表示相同與否,我在這裏用0表示相同,及T[i]=s[i],否則T[i]!=s[i] 我固定位置i, 向前遍歷 當到達位置t時, 令 (S[t] = T[t] ,S[t+1] = T[t+1]) S[i] 與T[i] 的關係分別討論。此時
若T[i]>S[i], t 每向前移動一位 , 滿足條件的子串就增加 n-i+1 個,我們若枚舉 j,則只需枚舉 j/(n-i+1) 次,整體複雜度爲n*n*log(n)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<cstring>
#include<vector>
#include<bitset>
#include<iterator>
#include<list>
#include<map>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
#define L p->ch[0]
#define R p->ch[1]
#define KeyTree root->ch[1]->ch[0]
typedef long long LL;
typedef pair<char, int> PII;
typedef vector<int> VI;
const int maxn = 2111;
const int INF = 1 << 30;
const int mod = (int) (1e9 + 7);
const LL X = 123;
template<typename T>
T gcd(T a, T b) {
return b ? gcd(b, a % b) : a;
}
LL dp[maxn][maxn][2];
char s[maxn];
int ch[maxn];
LL P[maxn];
int main() {
ios::sync_with_stdio(false);
int n, k, i, j, t, r;
cin >> n >> k;
cin >> (s + 1);
dp[0][0][1] = 1;
dp[0][0][0] = 0;
P[0] = 1;
for (i = 1; i <= n; ++i) {
ch[i] = (s[i] ^ 0x60);
}
r = n;
for (i = 1, r = n; i <= n; ++i, --r) {
for (j = 0; j <= k; ++j) {
dp[i][j][0] = dp[i][j][1] = dp[i - 1][j][0] + dp[i - 1][j][1];
LL& tv = dp[i][j][1];
tv = dp[i][j][1] * (ch[i] - 1) % mod;
for (t = i - 1; t >= 0 && j - (i - t) * r >= 0; --t) {
tv += (dp[t][j - (i - t) * r][1]) * (26 - ch[i]);
}
tv %= mod;
}
}
LL ans = (dp[n][k][0] + dp[n][k][1]) % mod;
cout << ans << endl;
return 0;
}