• [HAOI2018]染色



    题解

    我竟然能自己想出来计数题

    容斥+NTT
    首先一看到题目让求恰好出现(S)次的颜色有恰好(K)种就想到容斥
    如果容斥每种颜色出现次数的话并不好计数
    那么考虑容斥恰好出现(S)次的颜色有几种
    (F(i))表示恰好出现(S)次的颜色有至少(i)
    那么很显然(F(i) = C(n , iS) * C(m , i) * frac{(iS)!}{S!^i} * (m - i) ^ {n - iS})
    表示从(n)个位置中选出(iS)个位置用来涂这(i)种颜色,然后从(m)种颜色中选择了(i)种颜色,在选出的(iS)个位置每种颜色都涂上(S)个的方案数再乘上选剩下的(n-iS)个位置随便的放选剩下的(m-i)种颜色
    然后设(f(k))表示恰好出现(S)次的颜色有恰好(k)
    那么容斥就很显然了(f(k)=sum_{i=k}^{m}{(-1)^{i - k}C(i , k)F(i)})
    这样复杂度就是(O(n^2))
    然后考虑把这个(f(k))给化开
    (f(k)=sum_{i=k}^{m}{(-1)^{i-k}C(i,k)C(n,iS)C(m,i)frac{(iS)!}{S!^i}(m-i)^{n-iS}})
    然后把组合数都化开
    (f(k)=sum_{i=k}^{m}{(-1)^{i-k}frac{i!}{k!(i-k)!}frac{n!}{iS!(n-iS)!}frac{m!}{i!(m-i)!}frac{(iS)!}{S!^i}(m-i)^{n-iS}})
    然后把能消的都消掉就成了(f(k)=frac{n!m!}{k!}sum_{i=k}^{m}{frac{(-1)^{i-k}}{(i-k)!}frac{(m-i)^{n-iS}}{(n-iS)!(m-i)!S!^i}})
    然后可以发现后面那些东西可以设为(g(i))
    前面那些东西可以设为(t(i-k))
    那么把(g)倒过来卷积即可

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    # define LL long long
    const int M = 400005 ;
    const int N = 10000005 ;
    const int mod = 1004535809 ;
    const int G = 3 ;
    using namespace std ;
    
    inline int read() {
    	char c = getchar() ; int x = 0 , w = 1 ;
    	while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    	while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    	return x*w ;
    }
    
    int n , m , S , upp ;
    int val[M] , fac[N] ;
    int lim = 1 , len ;
    LL a[M] , b[M] , r[M] , ans ;
    
    inline int Fpw(int Base , int k) {
    	int temp = 1 ; Base = (Base % mod + mod) % mod ;
    	while(k) {
    		if(k & 1) temp = 1LL * temp * Base % mod ;
    		Base = 1LL * Base * Base % mod ; k >>= 1 ;
    	}
    	return temp ;
    }
    inline int inv(int x) {
    	x = (x % mod + mod) % mod ;
    	return Fpw(x , mod - 2) ;
    }
    inline void NTT(LL *A , int unit) {
    	for(int i = 1 ; i <= lim ; i ++) if(r[i] > i) swap(A[i] , A[r[i]]) ;
    	for(int mid = 1 ; mid < lim ; (mid <<= 1)) {
    		LL R = (mid << 1) ; LL W = Fpw(unit > 0 ? G : inv(G) , (mod - 1) / R) ;
    		for(int j = 0 ; j < lim ; j += R) {
    			LL w = 1 ;
    			for(int k = 0 ; k < mid ; k ++ , w = (w * W) % mod) {
    				LL x = A[j + k] , y = w * A[j + k + mid] % mod ;
    				A[j + k] = (x + y) % mod ; A[j + k + mid] = (x - y) % mod ;
    			}
    		}
    	}
    }
    int main() {
    	n = read() ; m = read() ; S = read() ;
    	for(int i = 0 ; i <= m ; i ++) val[i] = read() ;
    	if(S) upp = min(n / S , m) ; else upp = m ;
    	fac[0] = 1 ; for(int i = 1 ; i <= max(n , m) ; i ++) fac[i] = 1LL * fac[i - 1] * i % mod ;
    	for(int i = 0 ; i <= upp ; i ++) {
    		a[i] = 1LL * Fpw(m - i , n - i * S) * inv(fac[n - i * S]) % mod * inv(fac[m - i]) % mod * inv( Fpw( fac[S] , i ) ) % mod ;
    		b[i] = 1LL * Fpw(-1 , i) * inv(fac[i]) % mod ;
    	}
    	for(int i = 0 ; i <= upp / 2 ; i ++) swap(a[i] , a[upp - i]) ;
    	while(lim <= upp * 2) (lim <<= 1) , ++ len ;
    	for(int i = 1 ; i <= lim ; i ++) r[i] = ((r[i >> 1] >> 1) | ((i & 1) << (len - 1))) ;
    	NTT(a , 1) ; NTT(b , 1) ;
    	for(int i = 0 ; i <= lim ; i ++) a[i] = (a[i] * b[i] % mod + mod) % mod ;
    	NTT(a , -1) ; LL tinv = inv(lim) ;
    	for(int i = 0 ; i <= upp ; i ++) {
    		LL temp = (a[upp - i] * tinv % mod + mod) % mod ;
    		ans = (ans + 1LL * val[i] * temp % mod * fac[n] % mod * fac[m] % mod * inv(fac[i]) % mod) ;
    		ans = (ans % mod + mod) % mod ;
    	}
    	printf("%lld
    ",ans) ;
    	return 0 ;
    }
    
  • 相关阅读:
    性能测试——Jmeter基本用法概述
    Postman-newman基础用法
    数据库基础总结
    性能测试概述
    pytest+allure生成测试报告
    CSS入门基础
    HTML基础知识总结
    robotframework:无法导入资源Not a valid file or directory to import
    robotframework及官方编辑器RIDE的安装与配置
    常用排序算法
  • 原文地址:https://www.cnblogs.com/beretty/p/10486314.html
Copyright © 2020-2023  润新知