EOJ3536 求蛇形矩阵每一行的和---找规律

题目链接:

https://acm.ecnu.edu.cn/problem/3536/

题目大意:

求蛇形矩阵的每一行的和,数据范围n<=200000。

思路:

由于n数据较大,所以感觉应该是需要找规律。

先附上蛇形矩阵的打表代码,先输出数据较小的蛇形矩阵,观察规律。

 1 #include <iostream>
 2 #include <malloc.h>
 3 using namespace std;
 4 int arr[100][100];
 5 int startNum=1;
 6 void DrawCircle(int len,int n);
 7 int main(){
 8     int i,j,k,n,len;
 9     cout<<"请输入蛇形矩阵阶数n\nn=";
10     cin>>n;
11     len=n;
12     if(n%2!=0){
13         while(len>1){
14             DrawCircle(len,n);
15             len=len-2;
16         }
17         arr[n/2+1][n/2+1]=n*n;
18     }
19     else{
20         while(len>1){
21             DrawCircle(len,n);
22             len=len-2;
23         }
24     }
25     cout<<"对应的蛇形矩阵如下"<<endl;
26     for(i=1;i<=n;i++){
27         for(j=1;j<=n;j++){
28             cout<<arr[i][j];
29             if(j<n){
30                 if(arr[i][j]>=10)
31                     cout<<" ";
32                 else
33                     cout<<"  ";
34             }
35             else
36                 cout<<endl;
37         }
38     }
39     for(int i = 1; i <= n; i++)
40     {
41         int tot = 0;
42         for(int j = 1; j <= n; j++)tot += arr[i][j];
43         cout<<tot<<endl;
44     }
45     return 0;
46 }
47 void DrawCircle(int len,int n){
48     int i,number,row,col;
49     number=(n-len)/2+1;//当前画的是第几个圈
50     row=number;col=number;
51     for(i=1;i<=len;i++){
52         arr[row][col]=startNum++;
53         col++;
54     }
55     col--;//for循环要跳出时候,列数多加了一次,这个地方减掉
56     for(i=1;i<=len-1;i++){
57         row++;
58         arr[row][col]=startNum++;
59     }
60     for(i=1;i<=len-1;i++){
61         col--;
62         arr[row][col]=startNum++;
63     }
64     for(i=1;i<=len-2;i++){
65         row--;
66         arr[row][col]=startNum++;
67     }
68 }

举个例子,先观察n = 9的时候。

对应的蛇形矩阵如下

1  2  3  4  5  6  7  8  9
32 33 34 35 36 37 38 39 10
31 56 57 58 59 60 61 40 11
30 55 72 73 74 75 62 41 12
29 54 71 80 81 76 63 42 13
28 53 70 79 78 77 64 43 14
27 52 69 68 67 66 65 44 15
26 51 50 49 48 47 46 45 16
25 24 23 22 21 20 19 18 17


第一行的和是S1 = 9*10/2=45。

第二行前8位比第一行多31,第9位多1,S2 = 31*8+1+S1=294

第三行第2位到第7位比第二行多23, 第1位少1,后1位多1正好抵消,第8位多1,所以S3 = 23*6+1+S2=433

第四行第3位到第6位比第三行多15, 前2位少1,后2位多1正好抵消,第7位多1,所以S4 = 15*4+1+S3=494

第五行第4位到第5位比第三行多7, 前3位少1,后3位多1正好抵消,第6位多1,所以S5 = 7*2+1+S4=509

 这是上面的前半部分的规律,从a = 4 * n - 5(4*9-5=31), b = n - 1(9-1=8)开始,a依次减8,b依次减2

第六行比第五行前4位少1, 后4位多1,中间1位少3,S6 = S5-1*3=506

第七行比第六行前3位少1, 后3位多1,中间3位少11, S7 = S6 - 3*11=473

第八行比第七行前2位少1, 后2位多1,中间5位少19, S8 = S7 - 5*19=378

第九行比第八行前1位少1, 后1位多1,中间7位少27, S9 = S8 - 7*27=189

后半部分的规律是从a = 3, b = 1开始,a依次加8, b依次加2

 

以上是n为奇数的规律,偶数的规律也类似:
以n = 6为例:

对应的蛇形矩阵如下
1   2   3   4   5   6
20 21 22 23 24 7
19 32 33 34 25 8
18 31 36 35 26 9
17 30 29 28 27 10
16 15 14 13 12 11

前三行的规律和上面一样,

S1 = 6 * 7 / 2 = 21

S2 = 19 * 5 + 1 + S1=117

S3 = 11 * 3 + 1 + S2=151

后三行的规律是

S4 = S3 + 4

S5 = S4 - 2 * 7

S6 = S5 - 4 * 15

多找几组偶数会发现每次都是这样的规律,后半部分的第一行 = 前半部分的最后一行 + 4,然后的规律都是依次减去a*b,a最开始为2,b最开始为7,之后依次a+=2,b+=8.

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<string>
 6 #include<cmath>
 7 #include<set>
 8 #include<queue>
 9 #include<map>
10 #include<stack>
11 #include<vector>
12 #include<list>
13 #include<deque>
14 #include<sstream>
15 #include<cctype>
16 #define REP(i, n) for(int i = 0; i < (n); i++)
17 #define FOR(i, s, t) for(int i = (s); i < (t); i++)
18 #define MEM(a, x) memset(a, x, sizeof(a));
19 #define DEBUG(x) cout<<x<<endl;
20 #define DBG cout<<"----------------"<<endl;
21 #define mid(x, y) x + (y - x)/ 2
22 #define lc o<<1
23 #define rc o<<1|1
24 using namespace std;
25 typedef long long ll;
26 typedef unsigned long long ull;
27 typedef pair<int, int> Pair;
28 const int maxn = 1e6 + 10;
29 const double eps = 1e-10;
30 const int INF = 1e9;
31 const int dir[4][2] = {1,0,0,1,0,-1,-1,0};
32 const double pi = 3.1415926535898;
33 ll T, n, m, cases;
34 int main()
35 {
36     std::ios::sync_with_stdio(false);
37     cin >> n;
38     if(n & 1)//奇数的时候
39     {
40         ll a1 = (n + 1) * n / 2;//求出第一行
41         cout<<a1<<endl;
42         ll a = 4 * n - 5, b = n - 1;//a,b初始值
43         int i;
44         for(i = 2; i <= (n + 1) / 2; i++)//前半部分输出
45         {
46             a1 = a1 + 1 + a * b;
47             a -= 8;
48             b -= 2;
49             cout<<a1<<endl;
50         }
51         a = 3, b = 1;
52         for(;i <= n; i++)//后半部分输出
53         {
54             a1 = a1 - a * b;
55             cout<<a1<<endl;
56             a += 8;
57             b += 2;
58         }
59     }
60     else//n为偶数
61     {
62         ll a1 = (n + 1) * n / 2;//输出第一个
63         cout<<a1<<endl;
64         ll a = 4 * n - 5, b = n - 1;
65         int i;
66         for(i = 2; i <= (n + 1) / 2; i++)//前半部分和之前一样的规律
67         {
68             a1 = a1 + 1 + a * b;
69             a -= 8;
70             b -= 2;
71             cout<<a1<<endl;
72         }
73         a1 += 4;
74         cout<<a1<<endl;//中间的特殊规律
75         a = 2, b = 7;
76         i++;//这里i++保证输出正好n行
77         for(;i <= n; i++)//后半部分输出
78         {
79             a1 = a1 - a * b;
80             a += 2;
81             b += 8;
82             cout<<a1<<endl;
83         }
84     }
85     return 0;
86 }

注意坑点:最好所有的变量设成long long,如果n是int的话,计算a1 = (n + 1) * n / 2;的时候会溢出,导致出错。

 

posted @ 2018-03-30 23:11  _努力努力再努力x  阅读(1288)  评论(0编辑  收藏  举报