题目背景
小L通过泥萌的帮助,成功解决了牛栏的修建问题。奶牛们觉得主人非常厉害,于是再也不敢偷懒,母牛们奋力挤奶,生娃。子子孙孙无穷匮也!小L于是成为了一代富豪!
但是一直困扰小L的就是单身问题!小L经过长久的寻觅,小L终于找到了一个心仪的漂亮妹子。于是,小L打算在520那天给妹子一个惊喜!(虽然小L很节约,但是对妹子还是很阔绰的!)
题目描述
小L决定用K种珍珠为妹子做一串举世无双的珍珠垂饰。珍珠垂饰是由珍珠连接而成的,其长度可以认为就是珍珠垂饰上珍珠的个数。小L现在腰缠万贯,每种珍珠他都拥有N颗。根据将珍珠垂饰打开后珍珠不同的排列顺序可以区别不同种类的项链。现在,小L好奇自己可以组成多少种长度为1至N的不同的珍珠垂饰?当然,为显富有,每串珍珠垂饰都要必须由K种珍珠连成。 答案取模1234567891。
这一定难不倒聪明的你吧!如果你能帮小L解决这个问题,也许他会把最后的资产分给你1/4哦!
输入输出格式
输入格式:
输入包含多组数据。第一行是一个整数T,表示测试数据的个数。每组数据占一行,包含两个整数N和K,用一个空格隔开。
输出格式:
每组数据输出仅一行,包含一个整数,表示项链的种类数。
输入输出样例
2 2 1 3 2
2 8
说明
40 % :1<= N<= 100000, 0<= K<= 30
100% :T <= 10, 1<= N<= 1000000000, 0<= K<= 30
70%-100%:时限10ms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(超级麻烦的)组合数学+取模+容斥原理~
思路不难,实现好麻烦啊……
对于i个位置,一共有i^k+i^(k+1)+i^(k+2)+i^(k+3) ··· +i^n中种组合数,然后要去掉没有取够k种的,而g[i]-f[j]*C(j,i)就刚好是没有取全的,所以递推就可以求解。
取模运算超麻烦……这种写法好神奇的~
#include<cstdio>
#define modd 1234567891
#define ll long long
ll t,n,k,f[31],c[31][31],kk[31];
ll findd(ll u,ll v)
{
ll tot=1;
while(v)
{
if(v&1) tot=(u*tot)%modd;
u=(u*u)%modd;v>>=1;
}
return tot;
}
ll getc()
{
for(int i=0;i<=30;i++) c[i][0]=1;
for(int i=1;i<=30;i++)
for(int j=1;j<=i;j++) c[i][j]=c[i-1][j-1]+c[i-1][j];
}
int main()
{
getc();
for(int i=1;i<=30;i++) kk[i]=findd(i,modd-2);
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld",&n,&k);f[1]=(n-k+1)%modd;
for(ll i=2;i<=k;i++)
{
f[i]=((findd(i,n+1)-findd(i,k)+modd)%modd*kk[i-1]+modd)%modd;
for(ll j=1;j<i;j++) f[i]=(f[i]-f[j]*c[i][j]%modd+modd)%modd;
}
printf("%lld\n",f[k]);
}
return 0;
}