【HDU 3483】 A Very Simple Problem (二项式展开+矩阵加速)

A Very Simple Problem

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1022    Accepted Submission(s): 500


Problem Description
This is a very simple problem. Given three integers N, x, and M, your task is to calculate out the following value:

 

Input
There are several test cases. For each case, there is a line with three integers N, x, and M, where 1 ≤ N, M ≤ 2*10 9, and 1 ≤ x ≤ 50.
The input ends up with three negative numbers, which should not be processed as a case.

 

Output
For each test case, print a line with an integer indicating the result.

 

Sample Input
100 1 10000
3 4 1000
-1 -1 -1

 

Sample Output
5050
444

 

Source

 

【分析】

  感觉我的思想离正解还是太远太远,根本不会这样想。

  首先我们发现x很小,k很大,k达到了10^9,for一遍都不行,这样我们就想到ans可能存在递推式,然后可以用矩阵加速。

  

 

转自:http://972169909-qq-com.iteye.com/blog/1863402

 

  太厉害了,我自己都好难再推一次~~

 

代码如下:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<cmath>
 8 using namespace std;
 9 #define Maxn 60
10 #define LL long long
11 
12 LL c[Maxn][Maxn];
13 LL n,x,M;
14 
15 struct node
16 {
17     LL a[Maxn][Maxn];
18 }t[5];
19 
20 void init()
21 {
22     memset(c,0,sizeof(c));
23     for(LL i=0;i<=50;i++) c[i][0]=1;
24     for(LL i=1;i<=50;i++)
25      for(LL j=1;j<=50;j++)
26          c[i][j]=(c[i-1][j-1]+c[i-1][j])%M;
27 }
28 
29 void get_un()
30 {
31     memset(t[1].a,0,sizeof(t[1].a));
32     for(LL i=0;i<=x+1;i++) t[1].a[i][i]=1%M;
33 }
34 
35 void mul(LL now,LL y,LL z)
36 {
37     for(int i=0;i<=x+1;i++)
38      for(int j=0;j<=x+1;j++)
39      {
40          t[2].a[i][j]=0;
41          for(LL k=0;k<=x+1;k++)
42           t[2].a[i][j]=(t[2].a[i][j]+t[y].a[i][k]*t[z].a[k][j])%M;
43      }
44     t[now]=t[2];
45 }
46 
47 void qpow(LL b)
48 {
49     get_un();
50     while(b)
51     {
52         if(b&1) mul(1,0,1);
53         mul(0,0,0);
54         b>>=1;
55     }
56 }
57 
58 int main()
59 {
60     while(1)
61     {
62         scanf("%lld%lld%lld",&n,&x,&M);
63         if(n==-1&&x==-1&&M==-1) break;
64         init();
65         for(LL i=0;i<=x;i++)
66         {
67             for(LL j=0;j<=i;j++) t[0].a[i][j]=(x*c[i][j])%M;
68             for(LL j=i+1;j<=x+1;j++) t[0].a[i][j]=0;
69         }
70         for(LL i=0;i<x;i++) t[0].a[x+1][i]=0;
71         t[0].a[x+1][x]=t[0].a[x+1][x+1]=1%M;
72         // get_un();
73         qpow(n+1);
74         printf("%lld\n",t[1].a[x+1][0]);
75     }
76     return 0;
77 }
[HDU 3483]

 

2016-09-25 22:07:05

转载于:https://www.cnblogs.com/Konjakmoyu/p/5907143.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值