首页 > 代码库 > codeforces 100548F (西安现场赛F题):容斥原理

codeforces 100548F (西安现场赛F题):容斥原理

题目大意:

对n个排成一排的物品涂色,有m种颜色可选。

要求相邻的物品颜色不相同,且总共恰好有K种颜色,问所有可行的方案数

分析:

从m种颜色中选出k种,有c(m,k)种方法,那么我们只用考虑 k种颜色的涂法即可

显然第一个物品有k种涂法,后面的因为不能跟前面的相同都只有k-1种涂法

因此容易想到一个公式:k*(k-1)^(n-1)

但是这个公式算的是 不超过k种颜色的涂法,题目要求必须k种,怎么办呢?

先考虑一个简化版的问题:

用而且用完5种颜色涂不相关的五个物品的方案数

用阶乘的方法可以算出 ans=120,换一种思路呢想一想这个问题,容易想到

ans(取五种颜色)=5^5(取不大于5种颜色)-c(5,4)*4^5(取不大于4种颜色)

可是一算发现ans竟然小于0了,这是怎么回事呢?容易发现其实取小于四种颜色的方案被减重复了

于是想到需要容斥

ans=c(5,5)*5^5-c(5,4)*4^5+c(5,3)*3^5-c(5,2)*2^5+c(5,1)*1^5 =120

这个问题解决了。原问题也就差不多了。。

代码:

#include <iostream>#include <stdio.h>#include<string.h>#include<algorithm>#include<string>#include<ctype.h>using namespace std;const long long mod=1000000007;const long long ny=500000004;long long n,m,k;long long cm[1000010];long long cn[1000010];long long ck[1000010];long long inv[1000010];long long mo(long long x){    while(x<0)        x+=mod;    return x%mod;}long long exgcd(long long a,long long b,long long &x,long long &y){    if(a==0&&b==0) return -1;    if(b==0){x=1;y=0;return a;}    long long d=exgcd(b,a%b,y,x);    y-=a/b*x;    return d;}long long Inv(long long a,long long n){    long long x,y;    long long d=exgcd(a,n,x,y);    if(d==1) return (x%n+n)%n;    else return -1;}long long quickmod(long long a,long long b,long long m) //a^b%m{    long long res=1;    while(b)    {        if(b&1)            res=res*a%mod;        b>>=1;        a=a*a%mod;    }    return res;}void ini(){    cn[0]=cm[0]=1;    memset(cm,0,sizeof(cm));    cm[0]=1;    int tmp=min(m/2,k);    for(int i=1;i<=tmp;i++)    {        cm[i]=(cm[i-1]*(m+1-i)%mod*inv[i])%mod;    }    if(cm[k]==0)        cm[k]=cm[m-k];    ck[0]=ck[k]=1;    for(int i=1;i<=k/2;i++)    {        ck[i]=(ck[i-1]*(k+1-i)%mod*inv[i])%mod;        ck[k-i]=ck[i];    }}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    inv[1]=1;    for(int i=2;i<=1000000;i++)    {        inv[i]=Inv(i,mod);    }    int t;    scanf("%d",&t);    int cas=0;    while(t--)    {        cas++;        scanf("%I64d%I64d %I64d",&n,&m,&k);        ini();        long long ans=0;        long long p=1;        for(int i=k;i>=1;i--)        {            ans=(ans+p*((ck[k-i])*i%mod*quickmod(i-1,n-1,mod)%mod)+mod)%mod;            p=-p;        }        ans=(ans*cm[k])%mod;        printf("Case #%d:%c%I64d\n",cas, ,ans);    }    return 0;}

 

codeforces 100548F (西安现场赛F题):容斥原理