zoukankan      html  css  js  c++  java
  • 题解-CodeChef IOPC14L Sweets Problem

    Problem

    CodeChef-IOPC14L

    题目概要:给定 (n) 种糖果且给定每种糖果的数量 (A_i)(Q) 组询问,每次问选出 (S) 个糖果的方案数(模(10^9+7)

    (nleq 10^6,A_ileq 10^3,Qleq 10^4,Sleq 2 imes 10^3)

    Solution

    都说这题是容斥,但是始终不知道如何容斥,下面介绍一个母函数的做法

    这题想暴力首先可以想到将所有糖果的母函数乘起来。形式化的,对于一种糖果若有 (t) 个,则其母函数为 (sum_{i=0}^tx^i),将所有共 (n) 个母函数乘起来得到的(x^S)对应的系数即为答案

    问题转化为求所有母函数的积,设为 (F)

    考虑到 (nleq 10^6),暴力求积复杂度为 (O(nSlog S)),但(A_ileq 10^3),则考虑可以将本质相同的糖果合并一下,可以得出 (s[x]) 表示有 (x) 颗糖果的种类有多少,则

    [F=prod_{i=1}^{2000}(sum_{j=0}^ix^j)^{s[i]} ]

    这个东西的复杂度是 (O(S^2log Slog n)) 的,照理说已经比较优了,但还可以继续优化

    考虑到

    [sum_{i=0}^nx^i=frac {x^{n+1}-1}{x-1} ]

    所以上面的式子可以化为

    [F=prod_{i=1}^{2000}(frac {x^{i+1}-1}{x-1})^{s[i]} ]

    [F=frac {prod_{i=1}^{2000}(x^{i+1}-1)^{s[i]}}{(x-1)^n} ]

    上式中的分子由于每一项都是二项式的幂次,最终的答案可以利用Dp在 (O(ASln S)) 的时间内求得(其中(ln S)为级数求和复杂度)

    至于分母,视作 ((x-1)^{-n}),可以考虑

    [(1-x)^{-1}=frac 1{1-x}=sum_{i=0}^{+infty}x^i ]

    [(x-1)^{-n}=(-1)^n(1-x)^{-n}=(-1)^n(frac 1{1-x})^n=(-1)^n(sum_{i=0}^{+infty}x^i)^n ]

    发现那个 ((-1)^n) 很讨厌,于是将原式 (F) 的分母分子同时乘一个 ((-1)^n),由于 (sum s[i]=n),所以分子变为 (prod_{i=1}^{2000}(1-x^{i+1})^{s[i]}),同样可以利用Dp在 (O(ASln S)) 的时间内求得

    继续考虑分母,现在已经求得分母倒数为 ((sum_{i=0}^{+infty}x^i)^n),这个式子中 (x^k) 的项系数等价于将 (k) 分解为 (n) 个非负整数和的方案数,即(inom {n+k-1}{k})

    统计答案只需要分子与分母倒数做卷积即可,时间复杂度 (O(n+ASln S+S^2))

    Code

    另外,这道题不支持c++提交,整的我交了好多次才知道 c 与 c++ 的不同(比如说不能用取址符、不能用 const 定义出的数字去定义数组大小等)

    #include <stdio.h>
    #include <ctype.h>
    typedef long long ll;
    
    inline int read(){
    	char c11=getchar();int x = 0;
    	while(!isdigit(c11))c11=getchar();
    	while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
    	return x;
    }
    
    //const int N = 2001, M = 2001000, p = 1000000007;
    const int p = 1000000007;
    #define N 2001
    #define M 2001000
    int fac[M],inv[M],s[N];
    int f[N][N],Ans[N];
    int n;
    
    inline int qpow(int A,int B){
    	int res = 1;while(B){
    		if(B&1) res = (ll)res * A%p;
    		A = (ll)A * A%p, B >>= 1;
    	}return res;
    }
    
    inline int c(int nn,int mm){return (ll)fac[nn]*inv[mm]%p*inv[nn-mm]%p;}
    
    int main() {
    	fac[0] = f[0][0] = 1;
    	for(int i=1;i<M;++i) fac[i] = (ll)fac[i-1]*i%p;
    	inv[M-1] = qpow(fac[M-1],p-2);
    	for(int i=M-1;i;--i) inv[i-1] = (ll)inv[i]*i%p;
    	
    	n = read();
    	for(int i=1;i<=n;++i)++s[read()];
    	
    	for(int i=1;i<N;++i)
    		for(int j=0,t;j<=s[i] && (t = (i+1)*j)<N;++j)
    			if(j&1) for(int k=0;k+t<N;++k)
    				f[i][k+t] = (f[i][k+t] + (ll)c(s[i],j) * f[i-1][k]%p*(p-1))%p;
    			else for(int k=0;k+t<N;++k)
    				f[i][k+t] = (f[i][k+t] + (ll)c(s[i],j) * f[i-1][k])%p;
    	
    	for(int i=0;i<N;++i)
    		s[i] = c(n+i-1,i);
    	
    	for(int i=0;i<N;++i)
    		for(int j=0;j<=i;++j)
    			Ans[i] = (Ans[i] + (ll)f[N-1][j] * s[i-j])%p;
    	
    	int Q = read();
    	while(Q--) printf("%d
    ",Ans[read()]);
    	return 0;
    }
    
  • 相关阅读:
    一道打印的面试题
    Quartz使用总结
    子类和父类之间的静态代码块、静态方法、非静态代码块、构造函数之间的执行关系
    springboot使用 @EnableScheduling、@Scheduled开启定时任务
    springboot的Interceptor、Filter、Listener及注册
    ConcurrentHashMap 的工作原理及代码实现
    为什么Hashtable ConcurrentHashmap不支持key或者value为null
    Android 通过Java代码生成创建界面。动态生成View,动态设置View属性。addRules详解
    Android 自定义title 之Action Bar
    Android常用控件之GridView与ExpandableListView的用法
  • 原文地址:https://www.cnblogs.com/penth/p/10393679.html
Copyright © 2011-2022 走看看