日常补题——ICPC网络赛南京站第一题The beautiful values of the palace

The beautiful values of the palace

参考博文:https://blog.csdn.net/weixin_42856843/article/details/100559048

T: 1500ms
M: 524288K
judge:计蒜客
source:The Preliminary Contest for ICPC Asia Nanjing 2019

Description
Here is a square matrix of n∗nn * nn∗n, each lattice has its value (nnn must be odd), and the center value is n∗nn * nn∗n. Its spiral decline along the center of the square matrix (the way of spiral decline is shown in the following figure:)

 

The grid in the lower left corner is (1,1) and the grid in the upper right corner is (n , n)

Now I can choose mmm squares to build palaces, The beauty of each palace is equal to the digital sum of the value of the land which it is located. Such as (the land value is 123213123213123213,the beautiful values of the palace located on it is 1+2+3+2+1+3=12)(666−>18)(456−>15)1+2+3+2+1+3=12) (666 -> 18) (456 ->15)1+2+3+2+1+3=12)(666−>18)(456−>15)

Next, we ask ppp times to the sum of the beautiful values of the palace in the matrix where the lower left grid(x1,y1)

the upper right square (x2,y2)

Input
The first line has only one number TTT .Representing TTT-group of test data (T≤5)(T\le 5)(T≤5)

The next line is three number: n m pn \ m \ pn m p

The mm lines follow, each line contains two integers the square of the palace (x,y)

The pp lines follow, each line contains four integers : the lower left grid (x1,y1),the upper right square (x2,y2)

Output

Next, p1,p2,……,pn linesRepresent the answer in turn(n<=10^6)(m,p<=10^5)

样例输入
1
3 4 4
1 1
2 2
3 3
2 3
1 1 1 1
2 2 3 3
1 1 3 3
1 2 2 3

样例输出
5
18
23
17

PS:这题是看着别人的代码一步一步思考,理解过来的,代码基本上都是抄的ORZ,但是自己也确实是理解了,所以也算是学习的一种方式吧。

解题思路:

第一步:

  首先先通过找规律的方式,找到每一个坐标和它的值的关系。思考过程:先找到每一个x,y和它所在层数(圈数)的关系,这里我们通过与最中间的那一行和那一列来判断其所在层数。这里我们把最外围看作第一层(圈)。在成功找到层数之后,我们再根据其坐标来具体计算它的值(过程大家可以自己推一下,也不是很麻烦)。

下面是这个过程的代码:

 1 LL getval(LL x,LL y,LL n)
 2 {
 3     LL t=min(min(x,y),min(n-x+1,n-y+1));        //求出层数,最外面为第一层
 4     LL val=4*(n-t+1)*(t-1);
 5     if(x==(n-t+1)) val+=n-t-y+2;                //在第t层的右边
 6     else if(x==t) val+=2*n-5*t+y+3;             //在第t层的左边
 7     else if(y==(n-t+1)) val+=3*n-7*t+x+4;       //在第t层的上边
 8     else val+=2 * n - 3 * t - x + 3;            //在第t层的下边
 9     return val;
10 }

第二步:

  在这之后,我们可以构建一个数据结构来保存他每个点的信息

 1 struct point
 2 {
 3     LL x,y,val,pos,flag;
 4     point(){}
 5     point(LL x,LL y,LL val,LL pos,LL flag):x(x), y(y),  val(val) , pos(pos), flag(flag) {}
 6     bool operator < (point p) 7  { 8 if(x!=p.x) return x<p.x; 9 if(y!=p.y) return y<p.y; 10 return pos<p.pos; 11  } 12 };

解释一下,x,y是这个点的坐标,val则是这个点的漂亮值,pos用来判断它是要求的一个区域,还是一个点,flag用来判断这一块区域是要加上还是要减去

这里用到的思想是这样的

 

 这样将所有的数据按照 x 的顺序排序,就能很好的减少重复的操作和计算,因为你每遇到的一个需要求它的“前缀和”的点,它保证了它之前的x都比他小,这样就减少了很多需要考虑的东西!

下面贴下代码再解释一下:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long LL;
  4 const int maxn=1e6+5;
  5 #define lowbit(x) ((x)&(-x))
  6 
  7 //构造的数据结构
  8 struct point
  9 {
 10  LL x,y,val,pos,flag; 11  point(){} 12  point(LL x,LL y,LL val,LL pos,LL flag):x(x), y(y), val(val) , pos(pos), flag(flag) {} 13 bool operator < (point p) 14  { 15 if(x!=p.x) return x<p.x; 16 if(y!=p.y) return y<p.y; 17 return pos<p.pos; 18  } 19 }; 20 21 point a[maxn*2]; 22 LL tree[maxn*2]; 23 LL res[maxn]; 24 LL n,m,p,cnt; 25 26 LL getval(LL x,LL y,LL n) 27 { 28 LL t=min(min(x,y),min(n-x+1,n-y+1)); //求出层数,最外面为第一层 29 LL val=4*(n-t+1)*(t-1); 30 if(x==(n-t+1)) val+=n-t-y+2; //在第t层的右边 31 else if(x==t) val+=2*n-5*t+y+3; //在第t层的左边 32 else if(y==(n-t+1)) val+=3*n-7*t+x+4; //在第t层的上边 33 else val+=2 * n - 3 * t - x + 3; //在第t层的下边 34 return val; 35 } 36 37 LL getbeauty(LL a) 38 { 39 LL b=0; 40 while(a>0) 41  { 42 b+=a%10; 43 a/=10; 44  } 45 return b; 46 } 47 48 LL getsum(LL x,LL n) //树状数组得到要求的点的和 49 { 50 LL res=0; 51 while(x>0) 52  { 53 res+=tree[x]; 54 x-=lowbit(x); 55  } 56 return res; 57 } 58 59 void update(LL x,LL y,LL n) //树形数组的更新过程 60 { 61 while(x<=n) 62  { 63 tree[x]+=y; 64 x+=lowbit(x); 65  } 66 } 67 68 //初始化 69 void init() 70 { 71 memset(tree,0,sizeof(tree)); 72 memset(res,0,sizeof(res)); 73 cnt=0; 74 } 75 76 int main() 77 { 78  LL t,x1,y1,x2,y2,x,y; 79 scanf("%lld",&t); 80 while(t--) 81  { 82  init(); 83 scanf("%lld%lld%lld",&n,&m,&p); 84 for(LL i=0;i<m;++i) 85  { 86 scanf("%lld%lld",&x,&y); 87 LL k=getval(x,y,n); 88 LL kk=getbeauty(k); 89 a[cnt++]=point(x,y,kk,i,1); 90  } 91 for(LL i=m;i<m+p;++i) 92  { 93 scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2); 94 a[cnt++]=point(x2,y2,0,i,1); //一块大的矩阵 95 a[cnt++]=point(x1-1,y1-1,0,i,1); //一块最小的矩阵,也是多减的部分 96 a[cnt++]=point(x2,y1-1,0,i,-1); //下面的要减去的部分 97 a[cnt++]=point(x1-1,y2,0,i,-1); //左边的要减去的部分 98  } 99 sort(a,a+cnt); //按照x的顺序来排序 100 for(LL i=0;i<cnt;++i) 101  { 102 if(a[i].pos<m) //pos<m说明它是一个值点,更新 103  { 104  update(a[i].y,a[i].val,n); 105  } 106 else //否则就是要求前缀和的点,前面的x都小于我,所以就不用考虑x,然后用树状数组来维护y 107  { 108 res[a[i].pos-m]+=getsum(a[i].y,n)*a[i].flag; 109  } 110  } 111 for(int i=0;i<p;++i) 112 printf("%lld\n",res[i]); 113  } 114 return 0; 115 }

大家要是不明白,可以去原博看看,或者相互借鉴一下

再次谢谢这个大佬给我的思路

原博文:https://blog.csdn.net/qq_42369449/article/details/83047280

猜你喜欢

转载自www.cnblogs.com/bethebestone/p/11507904.html