zoukankan      html  css  js  c++  java
  • 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
    ",cas,' ',ans);
        }
        return 0;
    }
  • 相关阅读:
    MySQL学习笔记:coalesce
    Oracle学习笔记:decode函数
    MySQL学习笔记:like和regexp的区别
    状态图
    构件图和部署图
    java基础知识(一)
    包图
    活动图
    协作图
    序列图
  • 原文地址:https://www.cnblogs.com/oneshot/p/4155218.html
Copyright © 2011-2022 走看看