[国家集训队] 整数的lqp拆分

18.09.21模拟赛T1。

这实际上是zhx出的增强版。

考试的时候写了15分暴力,没推出来式子......

先看一下题:

洛谷 P4451 传送门

bzoj 2173 传送门

题面是一样的。

只不过,网上那道题的数据范围好小啊。

所以出题人zhx大佬把n的范围改成了1^18,把取模数改成了1^18+7。

式子:f[x]=2*f[x-1]+f[x-2]

矩阵乘法优化:

f[k-1] f[k-2]      乘        2  1    等于    f[k]  f[k-1]

   0       0                    1  0                 0      0

再写个快速乘就行了。

这么简单的题我居然没切......面壁。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define ll long long
 5 using namespace std;
 6 
 7 ll n;
 8 ll m=(ll)(1e18)+7;
 9 
10 struct matrix
11 {
12     ll a[2][2];
13 }f,g;
14 
15 ll multi(ll q,ll w)
16 {
17     ll ret=0;
18     while(w)
19     {
20         if(w&1)ret=(ret+q)%m;
21         q=(q+q)%m;
22         w>>=1;
23     }
24     return ret;
25 }
26 
27 matrix multi(matrix q,matrix w)
28 {
29     matrix e;
30     for(int i=0;i<=1;i++)
31     {
32         for(int j=0;j<=1;j++)
33         {
34             e.a[i][j]=0;
35             for(int k=0;k<=1;k++)
36             {
37                 e.a[i][j]=(e.a[i][j]+multi(q.a[i][k],w.a[k][j]))%m;
38             }
39         }
40     }
41     return e;
42 }
43 
44 matrix ksm(matrix b,ll p)
45 {
46     matrix ret=b;
47     p--;
48     while(p)
49     {
50         if(p&1)ret=multi(ret,b);
51         b=multi(b,b);
52         p>>=1;
53     }
54     return ret;
55 }
56 
57 int main()
58 {
59     freopen("RSA.in","r",stdin);
60     freopen("R5A.out","w",stdout);
61     scanf("%I64d",&n);
62     f.a[0][0]=0,f.a[0][1]=1;
63     g.a[0][0]=2;
64     g.a[0][1]=g.a[1][0]=1;
65     g=ksm(g,n);
66     f=multi(f,g);
67     printf("%I64d",f.a[0][0]);
68     fclose(stdin);
69     fclose(stdout);
70     return 0;
71 }
原文地址:https://www.cnblogs.com/cervusy/p/9688382.html