1. 程式人生 > >2016 pku campusH/OpenJ_POJ - C16H(推公式+矩陣快速冪)

2016 pku campusH/OpenJ_POJ - C16H(推公式+矩陣快速冪)

pow exist ref amp nbsp 多少 ica contain lines

傳送門:http://poj.openjudge.cn/practice/C16H?lang=en_US

  題面:描述

Wenwen has a magical ball. When put on an infinite plane, it will keep duplicating itself forever.

Initially, Wenwen puts the ball on the location (x0, y0) of the plane. Then the ball starts to duplicate itself right away. For every unit of time, each existing ball on the plane will duplicate itself, and the new balls will be put on the adjacent locations. The duplication rule of these balls is, during the i-th unit of time, a ball, which locates at (x, y), will duplicate ui

balls to (x, y+1), di balls to (x, y-1), li balls to (x-1, y) and ri balls to (x+1, y).

The duplication rule has a period of M. In another words, ui=ui-M, di=di-M, li=li-M, ri=ri-M, for i=M+1,M+2,...

Wenwen is very happy because she will get many balls. It is easy to calculate how many balls she will get after N units of time. However, she wants to know the sum of x-coordinates and y-coordinates of all balls after N units of time. This is a bit difficult for her. Could you help her? Since the sum might be very large, you should give the sum modulo 1,000,000,007 to her.

輸入The first line contains an integer T (1 ≤ T ≤ 25), indicating the number of test cases.

For each test case:

The first line contains four integers N (1 ≤ N ≤ 10^18), M (1 ≤ M ≤ 20,000), x0 and y0 (-10^18 ≤ x0,y0 ≤ 10^18);

Then follows M lines, the i-th line contains four integers: ui, di, li and ri (0 ≤ ui,di,li,ri ≤ 10,000).輸出For each test case, output one integer on a single line, indicating the sum of x-coordinates and y-coordinates of all balls after N units of time, modulo 1,000,000,007.樣例輸入

1
2 2 1 1
2 0 0 0
0 0 0 1

樣例輸出

19

提示In the Sample Input:

Initially, there is 1 ball on (1,1).

After 1 unit of time, there is 1 ball on (1,1) and 2 balls on (1,2);

After 2 units of time, there is 1 ball on (1,1), 2 balls on (1,2), 1 ball on (2,1) and 2 balls on (2,2).

Therefore, after 2 units of time, the sum of x-coordinates and y-coordinates of all balls is
(1+1)*1+(1+2)*2+(2+1)*1+(2+2)*2=19. 題意:給你一個處於x0,y0的球,會進行周期為M的變化。第i分鐘,所有的點會進行復制,使得會在(x,y+1)增加ui個球,在(x,y-1)處增加di個球,在(x-1,y)處增加li個球,在(x+1,y)處增加ri個球,問你在N時刻所有球的橫縱坐標的和為多少。 題目分析:

對於這個題目,首先我們得發現雖然題目說不需要求總的小球的數量,但是,如果我們得知了小球的總量的話,就可以很好的對橫縱坐標的和進行操作(只需要用總的個數乘上新增的個數,再加上前一個橫縱坐標的和乘上新的坐標的和即可)。 因此我們就可以發現這道題的遞推式: 對於總的小球的數量: allball[i]= allball[i-1]*(1+u[i]+d[i]+l[i]+r[i]); 而對於總的橫縱坐標的和: sum[i]=allball[i-1]*(1+u[i]+d[i]+l[i]+r[i])+sum[i-1]*(u[i]-d[i]-k[i]+r[i]); 得到了遞推的式子,我們就可以在O(n)的時間內求解出答案。但是對於這題來說,因為數據範圍為1e18,因此毫無疑問必須是用含有log的算法,於是我們就可以通過矩陣快速冪進行優化。 而因為這個遞推式是有一定的周期性的,因此,我們可以先求出第一個周期的矩陣,然後通過矩陣快速冪求出矩陣的(n/m)次冪,最後在乘上剩余的(n%m);  
 1 #include <bits/stdc++.h>
 2 #define maxn 100005
 3 using namespace std;
 4 const int mod=1e9+7;
 5 typedef long long ll;
 6 struct Matrix{
 7     ll mo[2][2];
 8     Matrix(){
 9         memset(mo,0,sizeof(mo));
10     }
11 };
12 Matrix Mul(Matrix x,Matrix y){
13     Matrix c;
14     for(int i=0;i<2;i++){
15         for(int j=0;j<2;j++){
16             for(int k=0;k<2;k++){
17                 c.mo[i][j]=(c.mo[i][j]+x.mo[i][k]*y.mo[k][j])%mod;
18             }
19         }
20     }
21     return c;
22 }
23 Matrix powmod(Matrix x,ll n){
24     Matrix res;
25     for(int i=0;i<2;i++){
26         res.mo[i][i]=1;
27     }
28     while(n){
29         if(n&1) res=Mul(res,x);
30         n>>=1;
31         x=Mul(x,x);
32     }
33     return res;
34 }
35 int A[maxn];
36 int B[maxn];
37 int main()
38 {
39     int t;
40     scanf("%d",&t);
41     while(t--){
42         ll n,m,x0,y0;
43         scanf("%lld%lld%lld%lld",&n,&m,&x0,&y0);
44         x0=(x0%mod+mod)%mod;
45         y0=(y0%mod+mod)%mod;
46         for(int i=0;i<m;i++){
47             int a,b,c,d;
48             scanf("%d%d%d%d",&a,&b,&c,&d);
49             A[i]=1+a+b+c+d;
50             B[i]=a-b+d-c;
51         }
52         Matrix base;
53         for(int i=0;i<2;i++){
54             base.mo[i][i]=1;
55         }
56         for(int i=0;i<m;i++){
57             Matrix tmp;
58             tmp.mo[0][0]=tmp.mo[1][1]=A[i],tmp.mo[1][0]=B[i];
59             base=Mul(base,tmp);
60         }
61         base=powmod(base,n/m);
62         for(int i=0;i<n%m;i++){
63             Matrix tmp;
64             tmp.mo[0][0]=tmp.mo[1][1]=A[i],tmp.mo[1][0]=B[i];
65             base=Mul(base,tmp);
66         }
67         cout<<(base.mo[1][0]+base.mo[1][1]*(x0+y0))%mod<<endl;
68     }
69     return 0;
70 }

2016 pku campusH/OpenJ_POJ - C16H(推公式+矩陣快速冪)