NOIP模拟题——小L的珍珠挂饰
【题目描述】
小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 70 % :1<= N<= 1000000000, 0<=K<=30时限 :1000ms 80%~100% :T <= 10, 1<= N<= 1000000000, 0<=K<=30 时限:50ms
30%:递推
设dp[i][j]为前i位置用j种颜色的方案数。状态转移方程:dp[i][j]=dp[i-1][j-1]*(k-j+1)+f[i-1][j]*j
70%:矩阵快速幂。
100%:容斥定理。。。。。。。
先枚举一个n 表示长度,那么方案数便是:
kn−C(k,1)∗ (k−1)n+C(k,2)∗ (k−2)n−C(k,3)∗ (k−3)n.....
即nk+Σ(−1)i∗ C(k,i)∗ (k−i)n
然而n 太大了,我们不能这样枚举n 来做,
故我们试着列出每个n 的长度的式子:
kn−C(k,1)∗ (k−1)n+C(k,2)∗ (k−2)n−C(k,3)∗ (k−3)n.....
kn−1−C(k,1)∗ (k−1)n−1+C(k,2)∗ (k−2)n−1−C(k,3)∗ (k−3)n−1.....
kn−2−C(k,1)∗ (k−1)n−2+C(k,2)∗ (k−2)n−2−C(k,3)∗ (k−3)n−2.....
然后我们把每个式子的每一项拿出来,便会发现这是等比数列!
于是我们便可以用等比数列求和公式很好的解决问题了。
1 #include<stdio.h>
2 #include<string.h>
3 #define L 30
4 #define mod 1234567891
5 typedef long long ll;
6 struct matrix
7 {
8 ll a[61][61];
9 }In,T,ans;
10 ll len;
11 matrix mul(matrix x,matrix y)
12 {
13 matrix ret;
14 for(ll i=0;i<=(len<<1);i++)
15 for(ll j=0;j<=(len<<1);j++)
16 {
17 ret.a[i][j]=0;
18 for(ll k=0;k<=(len<<1);k++)
19 ret.a[i][j]=(ret.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
20 }
21 return ret;
22 }
23 matrix pow(matrix x,ll y)
24 {
25 matrix ans=In;
26 while(y)
27 {
28 if(y&1)
29 {
30 ans=mul(ans,x);
31 }
32 x=mul(x,x);
33 y>>=1;
34 }
35 return ans;
36 }
37 int main()
38 {
39 freopen("pearl.in", "r", stdin);
40 freopen("pearl.out", "w", stdout);
41 ll t,c,n,m,i,j,k;
42 scanf("%lld",&t);
43 for(c=1;c<=t;c++)
44 {
45 scanf("%lld%lld",&n,&m);
46 len=m;
47 memset(ans.a,0,sizeof(ans.a));
48 memset(T.a,0,sizeof(T.a));
49 for(i=0;i<len;i++)
50 {
51 T.a[i][i]=i+2,T.a[i+len][i]=-i-1,In.a[i][i]=1;
52 if(i)
53 T.a[i-1][i]=i+1,T.a[i+len-1][i]=-i-1;
54 }
55 for(i=len;i<=(len<<1);i++)
56 T.a[i-len][i]=1,In.a[i][i]=1;
57 ans.a[0][0]=1;
58 ans=mul(ans,pow(T,n-1));
59 printf("%lld\n",(ans.a[0][m-1]+mod)%mod);
60 }
61 }