题意:给出$N$表示背包容量,且会给出$N$种物品,第$i$个物品大小为$i$,数量也为$i$,求装满这个背包的方案数,对$23333333$取模。$N \leq 10^5$
$23333333=17 \times 1372549$竟然不是质数性质太不优秀了(雾
直接跑背包$O(N^2)$,于是咱们考虑挖掘性质、分开计算
发现当$i < \sqrt{N}$时就是一个多重背包,用单调队列优化到$O(N \sqrt{N})$
而当$i \geq \sqrt{N}$时,选中物品的数量不会超过$\sqrt{N}$,又因为最小的物品大小为$\sqrt{N}$,所以我们可以设计一个DP:
设$dp_{i,j}$为放了$i$个物品,其中物品总重量为$j$时的方案总数,有
$$dp_{i,j}=dp_{i-1,j-\sqrt{N}}+dp_{i,j-i}$$
也就是两种转移:①多加一个$\sqrt{N}$②给所有物品$+1$
总复杂度为$O(N\sqrt{N})$
#include<bits/stdc++.h> #define MOD 23333333 #define MAXN 100001 using namespace std; } , g[][MAXN] = {} , allG[MAXN] = {}; int main(){ , dir = ; cin >> N; T = sqrt(N); ; i <= T ; i++) ; j < i ; j++){ , t = N / i * i + j; if(t > N) t -= i; int now = t; ; k <= i && t >= ; k++){ sum = (sum + f[t]) % MOD; t -= i; } ){ int q = f[now]; f[now] = sum; sum = (sum - q + MOD) % MOD; now -= i; ){ sum = (sum + f[t]) % MOD; t -= i; } } } ; i <= T ; i++){ dir ^= ; memset(g[dir] , , sizeof(g[dir])); ; j <= N ; j++){ g[dir][j] = (g[dir ^ ][j - (T + )] + g[dir][j - i]) % MOD; allG[j] = (allG[j] + g[dir][j]) % MOD; } } ; i <= N ; i++) ans = (ans + (long long)allG[i] * f[N - i]) % MOD; cout << ans; ; }