Live2D

题解 咱们去烧菜吧

题目传送门

题目大意

给出\(n,m\),表示有\(m\)种物品,第\(i\)种物品大小为\(a_i\),有\(b_i\)个。\(b_i=0\)时表示有无限个。对于\(i\in[1,m]\),求出有多少种方案使得选出的物品大小之和恰好为\(i\)

思路

就是一个套路题。

我们发现\(b_i=0\)时的生成函数为\(\dfrac{1}{1-x^{a_i}}\)\(b_i\not= 0\)时的答案为\(\dfrac{1-x^{a_i(b_i+1)}}{1-x^{a_i}}\)。答案的生成函数就是每个的生成函数之积。

但是直接搞显然不行,所以我们取\(\ln\)加起来再\(\exp\)一下。跟付公主的背包其实很想。

因为\(\ln(\dfrac{1-x^{a_i(b_i+1)}}{1-x^{a_i}})=\ln(1-x^{a_i(b_i+1)})-\ln(1-x^{a_i})\),又因为\(\ln(1-x)=\sum_{i=1}^{\infty} -\dfrac{1}{i}x^i\),所以我们可以发现拆开预处理,具体见代码。

于是,我们就可以在\(\Theta(n\ln n)\)的时间复杂度内解决这个问题。

话说学到了一个取模小技巧。

\(\texttt{Code}\)

#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline", "no-stack-protector", "unroll-loops")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"

#include <bits/stdc++.h>
using namespace std;

#define SZ(x) ((int)x.size())
#define Int register int
#define mod 998244353
#define MAXN 1000005

int upd (int x){return x + (x >> 31 & mod);}
int mul (int a,int b){return 1ll * a * b % mod;}
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;}
int qkpow (int a,int k){
	int res = 1;for (;k;k >>= 1,a = 1ll * a * a % mod) if (k & 1) res = 1ll * res * a % mod;
	return res;
}
int inv (int x){return qkpow (x,mod - 2);}

typedef vector <int> poly;

int w[MAXN],rev[MAXN];

void init_ntt (){
	int lim = 1 << 18;
	for (Int i = 0;i < lim;++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << 17);
	int Wn = qkpow (3,(mod - 1) / lim);w[lim >> 1] = 1;
	for (Int i = lim / 2 + 1;i < lim;++ i) w[i] = mul (w[i - 1],Wn);
	for (Int i = lim / 2 - 1;i;-- i) w[i] = w[i << 1];
}

void ntt (poly &a,int lim,int type){
#define G 3
#define Gi 332748118
	static unsigned long long d[MAXN];
	for (Int i = 0,z = 18 - __builtin_ctz(lim);i < lim;++ i) d[rev[i] >> z] = a[i];
	for (Int i = 1;i < lim;i <<= 1)
		for (Int j = 0;j < lim;j += i << 1)
			for (Int k = 0;k < i;++ k){
				int x = d[i + j + k] * w[i + k] % mod;
				d[i + j + k] = d[j + k] + mod - x,d[j + k] += x;
			}
	for (Int i = 0;i < lim;++ i) a[i] = d[i] % mod;
	if (type == -1){
		reverse (a.begin() + 1,a.begin() + lim);
		for (Int i = 0,Inv = inv (lim);i < lim;++ i) a[i] = mul (a[i],Inv);
	}
#undef G
#undef Gi 
}

poly operator + (poly a,poly b){
	a.resize (max (SZ (a),SZ (b)));
	for (Int i = 0;i < SZ (b);++ i) a[i] = add (a[i],b[i]);
	return a;
}

poly operator - (poly a,poly b){
	a.resize (max (SZ (a),SZ (b)));
	for (Int i = 0;i < SZ (b);++ i) a[i] = dec (a[i],b[i]);
	return a;
}

poly operator * (poly a,int b){
	for (Int i = 0;i < SZ (a);++ i) a[i] = mul (a[i],b);
	return a;
}

poly operator * (poly a,poly b){
	int d = SZ (a) + SZ (b) - 1,lim = 1;while (lim < d) lim <<= 1;
	a.resize (lim),b.resize (lim);
	ntt (a,lim,1),ntt (b,lim,1);
	for (Int i = 0;i < lim;++ i) a[i] = mul (a[i],b[i]);
	ntt (a,lim,-1),a.resize (d);
	return a;
}

poly operator << (poly a,int n){
	a.resize (SZ (a) + n);
	for (Int i = SZ (a) - 1;~i;-- i) a[i] = (i >= n ? a[i - n] : 0);
	return a;
}

poly inv (poly a,int n){
	poly b(1,inv (a[0])),c;
	for (Int l = 4;(l >> 2) < n;l <<= 1){
		c.resize (l >> 1);
		for (Int i = 0;i < (l >> 1);++ i) c[i] = i < n ? a[i] : 0;
		c.resize (l),b.resize (l);
		ntt (c,l,1),ntt (b,l,1);
		for (Int i = 0;i < l;++ i) b[i] = mul (b[i],dec (2,mul (b[i],c[i])));
		ntt (b,l,-1),b.resize (l >> 1);
	}
	b.resize (n);
	return b;
}

poly inv (poly a){return inv (a,SZ (a));}
poly der (poly a){
	for (Int i = 0;i < SZ (a) - 1;++ i) a[i] = mul (a[i + 1],i + 1);
	a.pop_back ();return a;
}
poly ine (poly a){
	a.push_back (0);
	for (Int i = SZ (a) - 1;i;-- i) a[i] = mul (a[i - 1],inv (i));
	a[0] = 0;return a;
}

poly ln (poly a,int n){
	a = ine (der (a) * inv (a));
	a.resize (n);
	return a;
}
poly ln (poly a){return ln (a,SZ (a));}

poly exp (poly a,int n){
	poly b (1,1),c;
	for (Int l = 2;(l >> 1) < n;l <<= 1){
		b.resize (l),c = ln (b);
		for (Int i = 0;i < l;++ i) c[i] = dec (i < n ? a[i] : 0,c[i]);
		c[0] = add (c[0],1);
		b = b * c,b.resize (l);
	}
	b.resize (n);
	return b;
}
poly exp (poly a){return exp (a,SZ (a));}

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

poly A;
int n,m,d[MAXN];

signed main(){
	init_ntt (),read (n,m),A.resize (n + 1);
	for (Int i = 1,a,b;i <= m;++ i){
		read (a,b);
		if (a <= n) d[a] ++;
		if (b && 1ll * a * (b + 1) <= n) d[a * (b + 1)] --; 
	}
	for (Int i = 1;i <= n;++ i) if (d[i]){
		d[i] = upd (d[i]);
		for (Int j = 1;i * j <= n;++ j) A[i * j] = add (A[i * j],mul (d[i],qkpow (j,mod - 2)));
	}
	A = exp (A);
	for (Int i = 1;i <= n;++ i) write (A[i]),putchar ('\n');
	return 0;
}
posted @ 2020-07-22 21:26  Dark_Romance  阅读(141)  评论(0编辑  收藏  举报