题目链接:
https://www.luogu.com.cn/problem/P2768
题目大意:
T组数据,对于每组数据,输入两个值n、k,表示有$k(kin[1,1000])$种宝石,每种宝石数量为$n(nin[1,10000000000])$且同种宝石之间完全相同.请你求出取出$x(xin[1,n])$个宝石且包含所有的k种宝石的排列个数.两个排列不同,当且仅当存在同一位置的两种宝石不同.
solution:
本题明显组合数学题,先观察若不受种类限制,则有$sum_{i=1}^{n}k^{i}$种,若限制有一种不能取,则有$C_{k}^{0}cdotsum_{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{xcdot (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(' '); }