[模拟赛] 新语言(lan)
题目描述:

解题思路:
考虑暴力dp,记状态 \(f_{i,j}\) 表示长度为 \(i\),开头为 \(j\),的合法方案数。
初值:
\[\sum _{i=\frac{n}{2}+1}^{n} f_{1,i}=1
\]
转移:
\[f_{i,j}= \sum _{k=j \times 2}^{n} f_{i-1,k}
\]
时间复杂度:\(O(NV)\)。
考虑优化。注意到每次 \(V\) 每次最少乘 \(2\)。所以假设没有 \(A_{i} \times 2 > N\) 则 \(A_{i+1}\) 没有限制,这一个串的长度不会超过 \(log V\)。那么加上这个限制之后,发现最终串是由一些单串组成的,所以我们可以只转移 \(log V\) 位,同时记 \(g_{i}\) 表示长度为 \(i\) 的合法单串。那么:
\[g_{i}=\sum _{j=1}^{n} f_{i,j}
\]
最后答案:
\[ans_{i}=\sum _{j=1}^{min(log V, i)} ans_{i-j} \times g_{j}
\]
代码实现:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10, mod = 1e9 + 7;
int n, m, f[30][N], g[30][N], ans[N];
void add(int &x, int y){x = (x + y) % mod;}
signed main(){
freopen("lan.in", "r", stdin);
freopen("lan.out", "w", stdout);
cin >> n >> m;
for(int i = n / 2 + 1; i <= n; i++) f[1][i] = 1;
for(int i = n; i >= 1; i--) g[1][i] = (f[1][i] + g[1][i + 1]) % mod;
for(int i = 2; i <= 20; i++){
for(int j = 1; j <= n; j++) f[i][j] = g[i - 1][j * 2];
for(int j = n; j >= 1; j--) g[i][j] = (f[i][j] + g[i][j + 1]) % mod;
}
ans[0] = 1;
for(int i = 1; i <= m; i++){
for(int j = max(0ll, i - 20); j < i; j++) add(ans[i], ans[j] * g[i - j][1] % mod);
}
cout << ans[m] << endl;
return 0;
}

浙公网安备 33010602011771号