码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-05-04 19:05:39      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:follow   lan   struct   duplicate   puts   int   tin   art   app   

传送门: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(推公式+矩阵快速幂)

标签:follow   lan   struct   duplicate   puts   int   tin   art   app   

原文地址:https://www.cnblogs.com/Chen-Jr/p/8992081.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!