题目大意
给出 (n),第 (i) 个数有 (i) 个,问凑出 (n) 的方案数。
(nle 10^5)
思路
呜呜呜,傻掉了。。。
首先想到根号分治,分别考虑 ([1,sqrt n]) 以及 ([sqrt n+1,n])。
- ([1,sqrt n])
不难看出这部分可以直接 dp,设 (f_{i,j}) 为前面 (i) 种物品选出重量为 (j) 的方案数,可以得到转移式:
[f_{i,j}=f_{i-1,j}+f_{i,j-i}-f_{i-1,j-i imes (i+1)}
]
- ([sqrt n+1,n])
不难看出这部分最多选出 (sqrt n) 个物品,于是可以设 (g_{i,j}) 表示选了 (i) 个 物品,选出重量为 (j) 的方案数。可以得到转移式:
[g_{i,j}=g_{i,j-i}+g_{i,j-sqrt n-1}
]
具体含义就是转移有两种,第一种就是集体右移,即重量为 (k) 的都变为 (k+1),另外一种就是选 (sqrt n+1)。
综上时空复杂度 (Theta(nlog n)),第一种记得滚动数组,不然会 MLE。
( exttt{Code})
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define mod 23333333
#define MAXN 100005
#define MAXM 325
template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int n,sqr;
int f[2][MAXN],g[MAXM][MAXN],f1[MAXN],f2[MAXN];
/*
f[i][j] 表示前面i个物品选出重量j的方案数,g[i][j]表示i个物品选出重量j的方案数
f[i][j]=f[i-1][j]+f[i][j-i]-f[i-1][j-i*(i+1)]
g[i][j]=g[i][j-i]+g[i-1][j-sqr-1]
*/
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
void Work1 (){
f[0][0] = 1;
for (Int i = 1;i <= sqr;++ i)
for (Int j = 0;j <= n;++ j)
f[i & 1][j] = add (f[i - 1 & 1][j],dec (j >= i ? f[i & 1][j - i] : 0,j >= i * (i + 1) ? f[i - 1 & 1][j - i * (i + 1)] : 0));
for (Int i = 0;i <= n;++ i) f1[i] = f[sqr & 1][i];
}
void Work2 (){
g[0][0] = 1;
for (Int i = 1;i <= sqr;++ i)
for (Int j = 0;j <= n;++ j)
g[i][j] = add (j >= i ? g[i][j - i] : 0,j >= sqr + 1 ? g[i - 1][j - sqr - 1] : 0);
for (Int i = 0;i <= n;++ i)
for (Int j = 0;j <= sqr;++ j) f2[i] = add (f2[i],g[j][i]);
}
signed main(){
read (n),sqr = sqrt (n),Work1(),Work2 ();
int ans = 0;for (Int i = 0;i <= n;++ i) ans = add (ans,1ll * f1[i] * f2[n - i] % mod);
write (ans),putchar ('
');
return 0;
}