[20200720NOIP提高组模拟T2]宝石垂坠

题目链接:

  https://www.luogu.com.cn/problem/P2768

题目大意:

  T组数据,对于每组数据,输入两个值n、k,表示有$k(k\in[1,1000])$种宝石,每种宝石数量为$n(n\in[1,10000000000])$且同种宝石之间完全相同.请你求出取出$x(x\in[1,n])$个宝石且包含所有的k种宝石的排列个数.两个排列不同,当且仅当存在同一位置的两种宝石不同.

solution:

 本题明显组合数学题,先观察若不受种类限制,则有$\sum_{i=1}^{n}k^{i}$种,若限制有一种不能取,则有$C_{k}^{0}\cdot\sum_{i=1}^{n}(k-1)^{i}$种......因此,可以使用容斥原理,令$G(x)=\sum_{i=1}^{n}x^{i}$,则本题答案即为$\sum_{i=0}^{k}(-1)^{i}C_{k}^{i}\cdot G(k-i)$.

  接下来即讨论如何高效求出$G(x)$.从结构上看,$G(x)$是一个等比数列,所以我们可以分类讨论:一、$x==1,G(x)=\sum_{i=1}^{n} 1=n$;二、$x>1,G(x)=\sum_{i=1}^{n} x^{i}=\frac{x\cdot (1-x^{n})}{1-x}=\frac{x^{n+1}-x}{x-1}$,接下来直接代入求解即可.

 

code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define R register
#define next exnttttnext
#define debug puts("MLG")
#define mod 1234567891
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writesp(ll x);
inline void writeln(ll x);
ll T,n,k;
inline ll quickpow(ll x,ll y){
    ll ans=1;
    for(;y;y>>=1){
        if(y&1)ans*=x,ans%=mod;
        x*=x,x%=mod;
    }
    return ans;
}
inline ll inv(ll x){
    return quickpow(x,mod-2);
}
ll jiecheng[3000];
inline void calc(){
    jiecheng[0]=1;
    for(R ll i=1;i<=2999;i++){
        jiecheng[i]=jiecheng[i-1]*i%mod;
    }
}
inline ll C(ll x,ll y){
    return jiecheng[x]*inv(jiecheng[y]*jiecheng[x-y]%mod)%mod;
}
inline ll G(ll x){
    return x==1?n:((quickpow(x,n+1)-x)*inv(x-1)%mod+mod)%mod;
}
ll ans,t;
int main(){
    calc();
    T=read();
    while(T--){
        n=read();k=read();
        ans=0;t=-1;
        for(R ll i=0;i<=k;i++){
            t=-t;
            ans+=t*C(k,i)*G(k-i);
            ans=(ans%mod+mod)%mod;
        }
        writeln(ans);
    }
}
inline ll read(){
    ll x=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') t=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*t;
}
inline void write(ll x){
    if(x<0){putchar('-');x=-x;}
    if(x<=9){putchar(x+'0');return;}
    write(x/10);putchar(x%10+'0');
}
inline void writesp(ll x){
    write(x);putchar(' ');
}
inline void writeln(ll x){
    write(x);putchar('\n');
}

 

 

posted @ 2020-07-20 17:00  月落乌啼算钱  阅读(183)  评论(2编辑  收藏  举报