• 「LOJ 556 Antileaf's Round」咱们去烧菜吧


    「LOJ 556 Antileaf's Round」咱们去烧菜吧

    最近在看 jcvb 的生成函数课件,顺便切一切上面讲到的内容的板子题,这个题和课件上举例的背包计数基本一样。

    解题思路

    首先列出答案的生成函数:

    [prod_{1leq k leq m}left(sum_{0leq ileq b_k} x^{ia_k} ight) \ =prod_{1leq kleq m}left(dfrac{1-x^{a_k{(b_k+1)}}}{1-x^{a_k}} ight) \ =expleft(sum_{1leq kleq m}ln(1-x^{a_k(b_k+1)})-ln(1-x^{a_k}) ight) \ =expleft(sum_{1leq kleq m}sum_{jgeq1}dfrac{x^{a_kj}-x^{a_k(b_k+1)j}}{j} ight) \ ]

    [c_k =sum_{1leq ileq m} [a_i=k] \d_k=sum_{1leq ileq m}[a_i(b_i+1)=k] \ A(x)=sum_{k}(c_k-d_k)x^k ]

    上面式子等价于

    [=expleft(sum_{jgeq1}dfrac{1}{j}sum_{k}(c_k-d_k)x^{jk} ight) \ =expleft(sum_{jgeq1}dfrac{1}{j}A(x^j) ight) ]

    因为过程始终在模 (x^{n+1}) 次下进行,所以 (A(x^j)) 有用的项只有 (lfloordfrac{n}{j} floor) 个,可以 (mathcal O(nlog n)) 预处理出

    [sum_{jgeq1}dfrac{1}{j}A(x^j) ]

    然后跑一遍多项式 (exp) 就好了,复杂度还是 (mathcal O(nlog n))

    这个题数据有问题,当 (a_i = 0) 的时候,第一步不能等比数列求和,然而通过此题需要无视 (a_i = 0) 的物品,甚至还有 (a_i=0,b_i=0) 的情况,所以下面贴一个AC代码,但是实际山来说不是正确的

    code

    /*program by mangoyang*/ 
    #include<bits/stdc++.h>
    #define inf (0x7f7f7f7f)
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    typedef long long ll;
    using namespace std;
    template <class T>
    inline void read(T &x){
        int ch = 0, f = 0; x = 0;
        for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
        for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
        if(f) x = -x;
    }
    const int N = (1 << 22) + 5, P = 998244353, G = 3;
    namespace poly{
    	int rev[N], W[N], invW[N], len, lg;	
    	inline int Pow(int a, int b){
    		int ans = 1;
    		for(; b; b >>= 1, a = 1ll * a * a % P)
    			if(b & 1) ans = 1ll * ans * a % P;
    		return ans;
    	}
    	inline void init(){
    		for(int k = 2; k < N; k <<= 1)
    			W[k] = Pow(G, (P - 1) / k), invW[k] = Pow(W[k], P - 2);
    	}
    	inline void timesinit(int lenth){
    		for(len = 1, lg = 0; len <= lenth; len <<= 1, lg++);
    		for(int i = 0; i < len; i++)
    			rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (lg - 1));
    	}
    	inline void DFT(int *a, int sgn){
    		for(int i = 0; i < len; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
    		for(int k = 2; k <= len; k <<= 1){
    			int w = ~sgn ? W[k] : invW[k];
    			for(int i = 0; i < len; i += k){
    				int now = 1;
    				for(int j = i; j < i + (k >> 1); j++){
    					int x = a[j], y = 1ll * a[j+(k>>1)] * now % P;
    					a[j] = (x + y) % P, a[j+(k>>1)] = (x - y + P) % P;
    					now = 1ll * now * w % P;
    				}
    			}
    		}
    		if(sgn == -1){
    			int Inv = Pow(len, P - 2);
    			for(int i = 0; i < len; i++) a[i] = 1ll * a[i] * Inv % P;
    		}
    	}
    	inline void getinv(int *a, int *b, int n){
    		static int tmp[N];
    		if(n == 1) return (void) (b[0] = Pow(a[0], P - 2));
    		getinv(a, b, (n + 1) / 2);
    		timesinit(n * 2 - 1);
    		for(int i = 0; i < len; i++) tmp[i] = i < n ? a[i] : 0;
    		DFT(tmp, 1), DFT(b, 1);
    		for(int i = 0; i < len; i++) 
    			b[i] = 1ll * (2 - 1ll * tmp[i] * b[i] % P + P) % P * b[i] % P;
    		DFT(b, -1);
    		for(int i = n; i < len; i++) b[i] = 0;
    		for(int i = 0; i < len; i++) tmp[i] = 0;
    	}
    	inline void getsqrt(int *a, int *b, int n){
    		static int tmp1[N], tmp2[N];
    		if(n == 1) return (void) (b[0] = 1);
    		getsqrt(a, b, (n + 1) / 2);
    		for(int i = 0; i < n; i++) tmp1[i] = a[i];
    		getinv(b, tmp2, n), timesinit(n * 2 - 1);
    		DFT(tmp1, 1), DFT(tmp2, 1);
    		for(int i = 0; i < len; i++) tmp1[i] = 1ll * tmp1[i] * tmp2[i] % P;
    		DFT(tmp1, -1);
    		for(int i = 0; i < len; i++) 
    			b[i] = 1ll * (b[i] + tmp1[i]) % P * Pow(2, P - 2) % P; 
    		for(int i = n; i < len; i++) b[i] = 0;
    		for(int i = 0; i < len; i++) tmp1[i] = tmp2[i] = 0;
    	}
    	inline void getln(int *a, int *b, int n){
    		static int tmp[N];
    		getinv(a, b, n), timesinit(n * 2 - 1);
    		for(int i = 1; i < n; i++) tmp[i-1] = 1ll * a[i] * i % P;
    		DFT(tmp, 1), DFT(b, 1);
    		for(int i = 0; i < len; i++) b[i] = 1ll * tmp[i] * b[i] % P;
    		DFT(b, -1);
    		for(int i = len - 1; i; i--) b[i] = 1ll * b[i-1] * Pow(i, P - 2) % P;
    		b[0] = 0;
    		for(int i = n; i < len; i++) b[i] = 0;
    		for(int i = 0; i < len; i++) tmp[i] = 0;
    	}
    	inline void getexp(int *a, int *b, int n){
    		static int tmp[N]; 
    		if(n == 1) return (void) (b[0] = 1);
    		getexp(a, b, (n + 1) / 2);
    		getln(b, tmp, n), timesinit(n * 2 - 1);
    		for(int i = 0; i < n; i++) tmp[i] = (!i - tmp[i] + a[i] + P) % P;
    		DFT(tmp, 1), DFT(b, 1);
    		for(int i = 0; i < len; i++) b[i] = 1ll * b[i] * tmp[i] % P;
    		DFT(b, -1);
    		for(int i = n; i < len; i++) b[i] = 0;
    		for(int i = 0; i < len; i++) tmp[i] = 0;
    	}
    	inline void power(int *a, int *b, int n, int m, ll k){
    		static int tmp[N];
    		for(int i = 0; i < m; i++) b[i] = 0;
    		int fir = -1;
    		for(int i = 0; i < n; i++) if(a[i]){ fir = i; break; }
    		if(fir && k >= m) return;
    		if(fir == -1 || 1ll * fir * k >= m) return;
    		for(int i = fir; i < n; i++) b[i-fir] = a[i];
    		for(int i = 0; i < n - fir; i++) 
    			b[i] = 1ll * b[i] * Pow(a[fir], P - 2) % P;
    		getln(b, tmp, m);
    		for(int i = 0; i < m; i++) 
    			b[i] = 1ll * tmp[i] * (k % P) % P, tmp[i] = 0;
    		getexp(b, tmp, m);
    		for(int i = m; i >= fir * k; i--) 
    			b[i] = 1ll * tmp[i-fir*k] * Pow(a[fir], k % (P - 1)) % P;
    		for(int i = 0; i < fir * k; i++) b[i] = 0;
    		for(int i = 0; i < m; i++) tmp[i] = 0;
    	}
    }
    using poly::Pow;
    using poly::DFT;
    using poly::timesinit;
    int a[N], b[N], A[N], f[N], g[N], n, m;
    int main(){
    	poly::init(), read(n), read(m);
    	for(int i = 1; i <= m; i++){
    		read(a[i]), read(b[i]);
    		if(!b[i]) b[i] = n / a[i];
    		if(a[i] <= n) A[a[i]]++;
    		if(1ll * a[i] * (b[i] + 1) <= n) A[a[i]*(b[i]+1)]--;
    	}
    	for(int i = 0; i <= n; i++) (A[i] += P) %= P;
    	for(int j = 1; j <= n; j++){
    		int Inv = Pow(j, P - 2);
    		for(int i = 1; i <= n / j; i++) 
    			(f[i*j] += 1ll * A[i] * Inv % P) %= P;
    	}
    	poly::getexp(f, g, n + 1);
    	for(int i = 1; i <= n; i++) printf("%d
    ", g[i]);
    	return 0;
    }
    
  • 相关阅读:
    希腊字母大全
    SQL 等值连接(内连接)、自然连接(Out join,Left join,Right join)的区别
    JDK11 JAVA11下载安装与快速配置环境变量教程
    “由爱故生忧,由爱故生怖。若离于爱者,无忧亦无怖”
    How to use special characters in XML?
    Crow’s Foot Notation
    How do I unmute my Lenovo laptop?
    Nginx学习笔记--001-Nginx快速搭建
    Nginx 相关介绍
    java使用httpclient封装post请求和get的请求
  • 原文地址:https://www.cnblogs.com/mangoyang/p/10693823.html
Copyright © 2020-2023  润新知