CF360C Levko and Strings
题目大意
给定一个长度为\(N\)模板字符串\(S\),由小写字母组成;
定义一个同样长度为\(N\)的字符串\(T\)的价值为:\(T\) 中子串在字典序下大于\(S\)中对
应下标子串的子串数量;
例如 \(S=′aabb′\) ,\(T=′bbbb′\),那么\(T\)的价值为\(7\)。
(区间 \([1, 1], [1, 2], [1, 3], [1, 4], [2, 2], [2, 3], [2, 4]\) 构成的子串,\(T\) 都对应大于 \(S\));
小 \(D\) 想知道有多少个由小写字母构成的字符串 \(T\) ,它的价值恰好为 \(K\); 对\(1e9+7\)取模
题解
首先想一个\(O(n^4)\)的暴力 设\(f[i][j][a][b]\)表示前\(i\)个位置有总共\(j\)个串大于\(S\)的串。有\(a\)个位置是从\(i\)开始
都和\(S\)相等,有\(b\)个开头位置已经满足某个位置大于\(S\)。每次枚举当前位置是等于小于还是大于。
然后考虑优化,我们发现只要统计大于\(S\)的位置产生的贡献贡献,如果这个位置是\(i\),它的前面有\(k\)个相等的位置,那就有
\((k+1)*(n-i+1)\)个串的贡献,左端点大于\(i\)的串都会在后面被统计到。这样优化到\(n^3\) 然后再想怎么优化
这个状态\(f[i][j][k]\)中间带有\(k\)这一维,我们要怎么去除这一维(其它维都不好去除)。我们考虑枚举有多少个位置是相等的
这样就可以至少在状态上去掉一维了。考试的时候就想到这里。于是一道蓝题就这样没做出来。
\(f[i][j]\)表示考虑前\(i\)个位置,最后一个位置要求不能填\(=\)的方案数。
\(1:\)填\(<\) 枚举前面的等号有多长 \(f[i][j]=\sum_{k=0}^{i-1}f[k][j]*(s[i]-'a')\) 可以前缀和优化
\(2:\)填\(>\) 也是枚举同样的 \(f[i][j]=\sum_{k=1}^{i}f[i-k][j-k*(n-i+1)]*('z'-s[i])\)
可以发现对于一个\(j\),我们枚举的转移的总次数是\(\sum_{i=1}^{i=n} \lfloor \frac{n}{i} \rfloor\)
总的复杂度是\(O(n^2logn)\) 平常还是别太好高骛远,脚踏实地做些简单题吧
CODE
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int N = 2111;
int n, K;
int f[N][N], sum[N];
char s[N];
int main(){
//freopen("string.in", "r", stdin);
cin>>n>>K>>s + 1;
for(int i = 1;i <= n; i++)s[i] -= 'a' - 1;
sum[0] = f[0][0] = 1;
int ans = !K;
for(int i = 1;i <= n; i++){
for(int j = 0;j <= K; j++){
(f[i][j] += 1LL * sum[j] * (s[i] - 1) % mod) %= mod;
for(int k = 1;k <= i && j >= k * (n - i + 1); k++){
(f[i][j] += 1LL * f[i-k][j-k*(n-i+1)] * (26 - s[i]) % mod) %= mod;
}
(sum[j] += f[i][j]) %= mod;
}
(ans += f[i][K]) %= mod;
}
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号