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;的时候会溢出,导致出错。