关于次数的dp
发现每个位置的性质除了在此处出现过多少次hello world外,还有其在新的hello world中可能的位置
设g[i][j]为以i为终点,构成helloworld的前j位的方案数
例如在字符串hhelloworld中,g[3][2] = 2;
于是发现
g[i][j] =
∑i−1k=1
g[k][j - 1],
使用前缀和维护,用sum[j - 1]更新g[i][j],用g[i][j]更新sum[j];
f[i]表示当前位出现过多少完整的helloworld
发现f[i]仅能由g[i][10]更新,即出现新的以i结尾的构成前10位(全串)的方案数
对答案贡献为g[i][10]
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define mod 1000000007
#define LL long long
using namespace std;
const int MAXN = 500000 + 50;
int n;
string s,x;
LL sum[MAXN],f[MAXN],g[MAXN][15];
char c;
int main(){
while(cin >> x){
s += x;
}
n = s.length();
for(int i = 0;i < n;i++){
if(s[i] >= 'A' && s[i] <= 'Z')s[i] += 32;
}
for(int i = 0;i < n;i++){
f[i] = f[i - 1];
if(s[i] == 'h'){
g[i][1] = 1;
sum[1]++;
}
else if(s[i] == 'e'){
g[i][2] = (sum[1]%mod + g[i][2]%mod)%mod;
sum[2] = (g[i][2]%mod + sum[2]%mod)%mod;
}
else if(s[i] == 'l'){
g[i][3] += sum[2];
g[i][3] %= mod;
g[i][4] += sum[3];
g[i][4] %= mod;
g[i][9] += sum[8];
g[i][9] %= mod;
sum[4] += g[i][4];
sum[4] %= mod;
sum[3] += g[i][3];
sum[3] %= mod;
sum[9] += g[i][9];
sum[9] %= mod;
}
else if(s[i] == 'o'){
g[i][5] += sum[4];
g[i][5] %= mod;
g[i][7] += sum[6];
g[i][7] %= mod;
sum[7] += g[i][7];
sum[7] %= mod;
sum[5] += g[i][5];
sum[5] %= mod;
}
else if(s[i] == 'w'){
g[i][6] += sum[5];
g[i][6] %= mod;
sum[6] += g[i][6];
sum[6] %= mod;
}
else if(s[i] == 'r'){
g[i][8] += sum[7];
g[i][8] %= mod;
sum[8] += g[i][8];
sum[8] %= mod;
}
else if(s[i] == 'd'){
g[i][10] += sum[9];
g[i][10] %= mod;
sum[10] += g[i][10];
sum[10] %= mod;
f[i] += g[i][10];//sum[10]包含了所有以前的串,g[i][10]为该位结尾的所有helloworld,故新增g[i][10]
f[i] %= mod;
}
}
printf("%lld",f[n - 1]);
return 0;
}
Tips:
明确各个数组的含义,保证在转移的时候符合实际
11.5
哇我好菜啊
我记录了那么多无用数组
直接把sum和g那个数组合并不就行了吗
还有f不就是一个变量吗
srO
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define mod 1000000007
using namespace std;
const int MAXN = 500000 + 50;
int dp[MAXN][15];
char s[] = {'#','h','e','l','l','o','w','o','r','l','d'};
string a,x;
char ss[MAXN];
int len,ans;
int main(){
while(cin >> x){
a += x;
}
len = a.length();
for(int i = 0;i < len;i ++){
if(a[i] >= 'A' && a[i] <= 'Z'){
a[i] += 32;
}
ss[i + 1] = a[i];
}
dp[0][0] = 1;
for(int i = 1;i <= len;i ++){
for(int j = 0;j <= 10;j ++){
dp[i][j] = dp[i - 1][j];
if(ss[i] == s[j] && j){
dp[i][j] = (dp[i - 1][j - 1]%mod + dp[i][j])%mod;
if(j == 10)ans = (ans + dp[i - 1][j - 1])%mod;
}
}
}
cout << ans;
}