[模拟赛] 新语言(lan)

题目描述:

QQ_1752903900641

解题思路:

考虑暴力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;
}
posted @ 2025-07-19 14:16  _huangweiliang  阅读(15)  评论(0)    收藏  举报