洛咕 P4491 [HAOI2018]染色

本文探讨了一个组合数学问题,计算在一个序列中,颜色出现特定次数的方案数。通过容斥原理和多项式乘法,使用NTT算法进行高效计算。
摘要由CSDN通过智能技术生成

显然颜色数量不会超过\(lim=\min(m,n/S)\)

考虑容斥,计算恰好出现了\(S\)次的颜色有至少\(i\)种的方案数\(f[i]\),钦定\(i\)种颜色正好放\(S\)

\(m\)种颜色选\(i\)种,所以乘一个\(C_m^i\)

然后这n个位置分成\(i+1\)个部分:被钦定的\(i\)种颜色,每个有\(S\)个;剩下的\(m-i\)种颜色,一共\(n-iS\)个。先看作是可重的全排列数,那么方案就有\(\frac{n!}{(S!)^i(n-iS)!}\)种。前\(i\)各部分都是只有一种颜色,后面部分每个有\(m-i\)种取法,所以还有一个\((m-i)^{n-iS}\)

综上,\(f[i]=C_m^i\cdot \frac{n!}{(S!)^i(n-iS)!}\cdot(m-i)^{n-iS}\)

接下来就是答案,恰好出现了\(S\)次的颜色有正好\(i\)种的方案数\(ans[i]\)

用容斥,\(ans[i]=\sum_{j=i}^{lim}(-1)^{j-i}C_j^if[j]\)

那个组合数很麻烦,拆开

\(ans[i]=\sum_{j=i}^{lim}(-1)^{j-i}\frac{j!}{i!(j-i)!}f[j]\)

\(ans[i]\cdot i!=\sum_{j=i}^{lim}\frac{(-1)^{j-i}}{(j-i)!}f[j]\cdot j!\)

这就可以直接用NTT做了,如果不知道怎么做的可以先写zjoi2014 力

#include<bits/stdc++.h>
#define il inline
#define vd void
#define mod 1004535809
typedef long long ll;
il int gi(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
il int pow(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=1ll*ret*x%mod;
        x=1ll*x*x%mod;y>>=1;
    }
    return ret;
}
#define inv(a) pow((a),mod-2)
const int G=3,iG=inv(G);
int fact[10000001],W[100010];
int A[262147],B[262147],rev[262147];
il int C(int n,int m){
    if(n<m)return 0;
    return 1ll*fact[n]*inv(1ll*fact[m]*fact[n-m]%mod)%mod;
}
il vd ntt(int*A,int n,int t){
    for(int i=0;i<n;++i)if(rev[i]>i)std::swap(A[rev[i]],A[i]);
    for(int o=1;o<n;o<<=1){
        int W=pow(t?G:iG,(mod-1)/(o<<1));
        for(int*p=A;p!=A+n;p+=o<<1)
            for(int i=0,w=1;i<o;++i,w=1ll*w*W%mod){
                int t=1ll*w*p[i+o]%mod;
                p[i+o]=(p[i]-t+mod)%mod,p[i]=(p[i]+t)%mod;
            }
    }
    if(!t){
        int invN=inv(n);
        for(int i=0;i<n;++i)A[i]=1ll*invN*A[i]%mod;
    }
}
int main(){
    int n=gi(),m=gi(),s=gi();
    for(int i=0;i<=m;++i)W[i]=gi();
    int LIM=std::max(m,n);
    fact[0]=1;for(int i=1;i<=LIM;++i)fact[i]=1ll*fact[i-1]*i%mod;
    int lim=std::min(m,n/s);
    int N=1,lg=0;while(N<(lim+1)<<1)N<<=1,++lg;
    for(int i=0;i<=lim;++i)A[i]=1ll*fact[i]*C(m,i)%mod*fact[n]%mod*pow(m-i,n-i*s)%mod*inv(1ll*pow(fact[s],i)*fact[n-i*s]%mod)%mod;
    for(int i=0;i<=lim;++i){
        B[i]=inv(fact[lim-i]);
        if((lim-i)&1)B[i]=mod-B[i];
    }
    for(int i=0;i<N;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<lg-1);
    ntt(A,N,1),ntt(B,N,1);
    for(int i=0;i<N;++i)A[i]=1ll*A[i]*B[i]%mod;
    ntt(A,N,0);
    int ans=0;
    for(int i=0;i<=lim;++i)ans=(ans+1ll*W[i]*A[lim+i]%mod*inv(fact[i])%mod)%mod;
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/xzz_233/p/10076894.html

内容概要:该题库专为研究生入学考试计算机组成原理科目设计,涵盖名校考研真题、经典教材课后习题、章节题库和模拟试题四大核心模块。名校考研真题精选多所知名高校的计算机组成原理科目及计算机联考真题,并提供详尽解析,帮助考生把握考研命题趋势与难度。经典教材课后习题包括白中英《计算机组成原理》(第5版)和唐朔飞《计算机组成原理》(第2版)的全部课后习题解答,这两部教材被众多名校列为考研指定参考书目。章节题库精选代表性考题,注重基础知识与重难点内容,帮助考生全面掌握考试大纲要求的知识点。模拟试题依据历年考研真题命题规律和热门考点,精心编制两套全真模拟试题,并附标准答案,帮助考生检验学习成果,评估应试能力。 适用人群:计划参加研究生入学考试并报考计算机组成原理科目的考生,尤其是需要系统复习和强化训练的学生。 使用场景及目标:①通过研读名校考研真题,考生可以准确把握考研命题趋势与难度,有效评估复习成效;②通过经典教材课后习题的练习,考生可以巩固基础知识,掌握解题技巧;③通过章节题库的系统练习,考生可以全面掌握考试大纲要求的各个知识点,为备考打下坚实基础;④通过模拟试题的测试,考生可以检验学习成果,评估应试能力,为正式考试做好充分准备。 其他说明:该题库不仅提供详细的题目解析,还涵盖了计算机组成原理的各个方面,包括计算机系统概述、数据表示与运算、存储器分层、指令系统、中央处理器、总线系统和输入输出系统等。考生在使用过程中应结合理论学习与实践操作,注重理解与应用,以提高应试能力和专业知识水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值