zoukankan      html  css  js  c++  java
  • [洛谷P4491] HAOI2018 染色

    问题描述

    为了报答小 C 的苹果, 小 G 打算送给热爱美术的小 C 一块画布, 这块画布可 以抽象为一个长度为 (N) 的序列, 每个位置都可以被染成 (M) 种颜色中的某一种.

    然而小 C 只关心序列的 (N) 个位置中出现次数恰好为 (S) 的颜色种数, 如果恰 好出现了 (S) 次的颜色有 (K) 种, 则小 C 会产生 (W_k) 的愉悦度.

    小 C 希望知道对于所有可能的染色方案, 他能获得的愉悦度的和对 (1004535809) 取模的结果是多少。

    输入格式

    从标准输入读入数据. 第一行三个整数 (N, M, S).

    接下来一行 (M + 1) 个整数, 第 (i) 个数表示 (W_{i-1}).

    输出格式

    输出到标准输出中. 输出一个整数表示答案.

    样例输入

    8 8 3
    3999 8477 9694 8454 3308 8961 3018 2255 4910

    样例输出

    524070430

    数据范围

    (Nle 10^7, Mle 10^5, Sle 150)

    解析

    考虑容斥。设 (f_i) 表示至少有 (i) 种颜色出现了 (S) 次的方案数。实际上钦定出现了 (S) 次的颜色后就是一个可重排列,没有被钦定的颜色任意选择。即:

    [f_i={mchoose i} frac{n!}{(S!)^i(n-iS)!} (n-iS)^{m-i} ]

    (g_i) 表示恰好有 (i) 种颜色出现了 (S) 次的方案数。不难得到:

    [egin{aligned}g_i&=sum_{j=i}^m (-1)^{j-i}{jchoose i} f_j\ &=sum_{j=i}^m frac{(-1)^{j-i}}{(j-i)!} imes j!f_jend{aligned} ]

    差卷积一下即可。

    代码

    #include <iostream>
    #include <cstdio>
    #define N 10000002
    #define M 500002
    #define int long long
    using namespace std;
    const int mod=1004535809;
    const int G=3;
    int n,m,n1=1,m1,lim,s,i,w[M],f[M],g[M],r[M],fac[N],inv[N];
    int read()
    {
    	char c=getchar();
    	int w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    int poww(int a,int b)
    {
    	int ans=1,base=a;
    	while(b){
    		if(b&1) ans=ans*base%mod;
    		base=base*base%mod;
    		b>>=1;
    	}
    	return ans;
    }
    int C(int n,int m)
    {
    	return fac[n]*inv[m]%mod*inv[n-m]%mod;
    }
    void NTT(int *a,int n,int inv)
    {
    	for(int i=0;i<n;i++){
    		if(i<r[i]) swap(a[i],a[r[i]]);
    	}
    	for(int l=2;l<=n;l<<=1){
    		int mid=l/2;
    		int cur=poww(G,(mod-1)/l);
    		if(inv==-1) cur=poww(cur,mod-2);
    		for(int i=0;i<n;i+=l){
    			int omg=1;
    			for(int j=0;j<mid;j++,omg=omg*cur%mod){
    				int tmp=omg*a[i+j+mid]%mod;
    				a[i+j+mid]=(a[i+j]-tmp+mod)%mod;
    				a[i+j]=(a[i+j]+tmp)%mod;
    			}
    		}
    	}
    	if(inv==-1){
    		for(int i=0;i<n;i++) a[i]=a[i]*poww(n,mod-2)%mod;
    	}
    }
    signed main()
    {
    	n=read();m=read();s=read();
    	for(i=0;i<=m;i++) w[i]=read();
    	for(i=fac[0]=1;i<=max(n,m);i++) fac[i]=fac[i-1]*i%mod;
    	inv[max(n,m)]=poww(fac[max(n,m)],mod-2);
    	for(i=max(n,m)-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
    	m1=min(m,n/s);
    	for(i=0;i<=m1;i++) f[i]=fac[i]*C(m,i)%mod*fac[n]%mod*poww(inv[s],i)%mod*inv[n-s*i]%mod*poww(m-i,n-i*s)%mod;
    	for(i=0;i<=m1;i++){
    		g[i]=inv[m1-i];
    		if((m1-i)%2!=0) g[i]=mod-g[i];
    	}
    	while(n1<=2*m1) n1<<=1,lim++;
    	for(i=0;i<n1;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(lim-1));
    	NTT(f,n1,1);NTT(g,n1,1);
    	for(i=0;i<n1;i++) f[i]=f[i]*g[i]%mod;
    	NTT(f,n1,-1);
    	int ans=0;
    	for(i=0;i<=m1;i++) ans=(ans+w[i]*f[m1+i]%mod*inv[i]%mod)%mod;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Go 语言简介(下)— 特性
    Array.length vs Array.prototype.length
    【转】javascript Object使用Array的方法
    【转】大话程序猿眼里的高并发架构
    【转】The magic behind array length property
    【转】Build Your own Simplified AngularJS in 200 Lines of JavaScript
    【转】在 2016 年做 PHP 开发是一种什么样的体验?(一)
    【转】大话程序猿眼里的高并发
    php通过token验证表单重复提交
    windows 杀进程软件
  • 原文地址:https://www.cnblogs.com/LSlzf/p/13554400.html
Copyright © 2011-2022 走看看