zoukankan      html  css  js  c++  java
  • Gym 100548F Color 给花染色 容斥+组合数学+逆元 铜牌题

    Problem F. Color
    Description
    Recently, Mr. Big recieved n flowers from his fans. He wants to recolor those flowers with
    m colors. The flowers are put in a line. It is not allowed to color any adjacent flowers with
    the same color. Flowers i and i + 1 are said to be adjacent for every i, 1 ≤ i < n. Mr. Big
    also wants the total number of different colors of the n flowers being exactly k.
    Two ways are considered different if and only if there is at least one flower being colored
    with different colors.
    Input
    The first line of the input gives the number of test cases, T. T test cases follow. T is about
    300 and in most cases k is relatively small.
    For each test case, there will be one line, which contains three integers n, m, k (1 ≤ n, m ≤
    109
    , 1 ≤ k ≤ 106
    , k ≤ n, m).
    Output
    For each test case, output one line containing “Case #x: y”, where x is the test case
    number (starting from 1) and y is the number of ways of different coloring methods modulo
    109 + 7.
    Samples
    Sample Input Sample Output
    2
    3 2 2
    3 2 1
    Case #1: 2
    Case #2: 0

    题意:给你N朵花,M种颜料(n,m<=1e9),要求给所有花染色,且相邻的花不能用同样的颜色,求出最后恰好用了k种

    颜料的方案数(k<=1e5)

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    #include <stack>
    #include <queue>
    #include <vector>
    #define MM(a,b) memset(a,b,sizeof(a));
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    #define CT continue
    #define SC scanf
    const int N=1e6+10;
    const int mod=1e9+7;
    int cas,n,m,k,kk;
    ll C[N],inv[N];
    
    ll _pow(ll a,ll b)
    {
        ll res=1;
        while(b){
            if(b&1) res=(res*a)%mod;
            a=(a*a)%mod;
            b>>=1;
        }
        return res;
    }
    
    void  init_yuan()
    {
       inv[1]=1;
       for(int i=2;i<=1e6;i++){
           inv[i]=(mod-mod/i)*inv[mod%i]%mod;
       }
    }//求逆元模板  
    
    void init_cki()
    {
        C[0]=1;
        for(int i=0;i<k;i++){
            C[i+1]=C[i]*(k-i)%mod*inv[i+1]%mod;
        }
    }//预处理C(k,i)
    
    ll c(ll m,ll k)
    {
        ll res=1;
        k=min(k,m-k);
        for(int i=0;i<k;i++){
            res=res*(m-i)%mod;
        }
        for(int i=0;i<k;i++){
            res=res*inv[i+1]%mod;
        }
        return res;
    }//求C(m,k)
    
    int main()
    {
        kk=0;
        init_yuan();
        SC("%d",&cas);
        while(cas--) {
            SC("%d%d%d",&n,&m,&k);
            init_cki();
            ll ans=k*_pow(k-1,n-1)%mod,res=0;
            for(int i=1;i<=k-2;i++) {
                if(i%2) res+=C[i]*(k-i)%mod*_pow(k-i-1,n-1)%mod;
                else res=(res-C[i]*(k-i)%mod*_pow(k-i-1,n-1)+mod)%mod;
            }
            ans=(ans-res+mod)%mod;
            ans=(ans*c(m,k))%mod;
            printf("Case #%d: %lld
    ",++kk,ans);
        }
        return 0;
    }
    

      错因分析:刚开始想的是直接在n上容斥,,果然是太过复杂,,,就挂了;;

    解答:1.可以转换下思路,,如果当前选了k种,那么涂完后花的颜色不超过k种的方案数为S=k*_pow(k-1,n-1),想象其是一个集合,设a[i](1<=i<=k)代表第i种颜料并没有用到,那么那么此情况下答案就为S-(a[1]并a[2]并...a[k])的面积,但是后面这个部分肯定是a[1]和a[2]等这些存在交集,所以就需要容斥了,最后因为存在C(m,k)种情况所以答案出来后还要乘C(m,k)

    2.除法取模需要用到逆元见资料

  • 相关阅读:
    为什么用strlcpy取代strncpy
    linux系统调用和库函数调用的区别
    VC、PE和天使投资是什么意思?有什么区别?
    AWS使用心得:当初我曾错过的那些宝贵经验
    bzoj 2208: [Jsoi2010]连通数
    android学习笔记(5)Activity生命周期学习
    Nginx 进程间通信
    手写一个节点大小平衡树(SBT)模板,留着用
    JavaFX学习之道:JavaFX之TableView
    Docker 命令行和后台參数
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5840630.html
Copyright © 2011-2022 走看看