2019 南京网络赛A The Beautiful values of the palace (用时间模拟x轴)

题意:
给你一个宽度为奇数的正方形,每个块都有一定的权值,把权值的每一位加起来得到每一个块的“美丽值”。现在告诉你正方形中有一些块上面建造的有宫殿,然后问你在某一个矩形区域内所有宫殿的“美丽值”的总和。

在网上看了别人的解答,在此记录

(注意,一个函数的返回值是 ll (long long) 的话或者内部需要使用 ll ,这个函数内部就不应该出现int,否则可能出现隐式越界,难以察觉)

题目有两个难点
第一 要在O(1)的时间内算出螺旋矩阵的值,
螺旋矩阵可以分圈算,因为每圈的数字的数量是一个等差数列。
第一步,算出要求的点所在的圈数,

ll q = min(min(x, y), min(n - x + 1, n - y + 1));

第二步,算出它是圈里面的第几个数(同一圈里面的数单调递增),

	if (x == y && y == q)
		num = 1;
	else if (y > x)
		num = x + y - 2 * q + 1;
	else
		num = 4 * (n - 2 * q + 1) - (x + y - 2 * q) + 1;

第三步,算出他所在的圈的第一个元素的值(每圈的元素的数量为等差数列,用求和公式可以算出),在加上刚刚算出的num,就是元素的值。

ll get(ll x, ll y, ll n) {//get(n-x+1, n-y+1,n)
	int q = min(min(x, y), min(n - x + 1, n - y + 1));
	ll num;
	if (x == y && y == q)
		num = 1;
	else if (y > x)
		num = x + y - 2 * q + 1;
	else
		num = 4 * (n - 2 * q + 1) - (x + y - 2 * q) + 1;
	return  num+2 * ((n - 1) + (n - 2 * (q - 1) + 1))*(q - 1);
}

第二个难点在于在O(1)或者O(lgn)的时间内求出一个区间的值之和,用二维的树状数组可以很好的解决问题,但是这样空间不允许。有个好办法就是用前缀和加线段树,
在这里插入图片描述
所以只需要求出A B C D就可以求出M。具体方法可以把M保存为ABCD四个顶点的坐标(ABCD的右下角坐标),把可用的点的坐标也保存进来,把这些数据按照X轴排序,同时想到到y坐标的,所以遇到点就加入树状数组,遇到区间就用树状数组求和。因为是按照x后排序的,所以可以保证x和y都慢猪条件(要求的区间是从(0,0)开始的)。
代码如下

#include <iostream>
#include <cstdio>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>
#include <stack>

#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define l(x) ((x)<<1)
#define r(x) ((x)<<1|1)
#define lowbit(x) ((x)&(-(x)))
#define abs(x) ((x)>=0?(x):(-(x)))
#define ms(a,b) memset(a,b,sizeof(a))

using namespace std;

struct node {
	ll x, y;
	ll flag, pos, val;
	node(ll xx,ll yy,ll ff,ll pp,ll vv):x(xx),y(yy),flag(ff),pos(pp),val(vv){}
	node():node(0,0,0,0,0){}
	friend bool operator<(const node & a,const node&t) {
		if (a.x != t.x) return a.x < t.x;
		if (a.y != t.y)return a.y < t.y;
		return a.pos < t.pos;
	}
};

int m, n,p,len;
ll bit[1000005*2];
node a[1000005*2];
ll ans[1000005];

ll sum(ll i) {
	ll s = 0;
	while (i > 0) {
		s += bit[i];
		i -= lowbit(i);
	}
	return s;
}

void add(ll i, ll x) {
	while (i <= n) {
		bit[i] += x;
		i += lowbit(i);
	}
}

ll get(ll x, ll y, ll n) {//get(n-x+1, n-y+1,n)
	int q = min(min(x, y), min(n - x + 1, n - y + 1));
	ll num;
	if (x == y && y == q)
		num = 1;
	else if (y > x)
		num = x + y - 2 * q + 1;
	else
		num = 4 * (n - 2 * q + 1) - (x + y - 2 * q) + 1;
	return  num+2 * ((n - 1) + (n - 2 * (q - 1) + 1))*(q - 1);
}

void init() {
	ms(bit, 0);
	ms(ans, 0);
	len = 0;
}

void solve() {
	scanf("%d%d%d", &n, &m, &p);
	ll x, y;
	ll tt,temp;
	for (int i = 0; i < m; i++) {
		scanf("%lld%lld", &x, &y);
		tt = get(n-x+1, n-y+1, n);
		temp = 0;
		while (tt) {
			temp += tt % 10;
			tt /= 10;
		}
		a[len++] = node(x, y, 0, i, temp);
	}
	ll x1, y1, x2, y2;
	for (int i = m; i <= m + p-1; i++) {
		scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
		a[len++] = node(x1 - 1, y1 - 1, 1, i, 0);
		a[len++] = node(x2, y1 - 1, -1, i, 0);
		a[len++] = node(x1 - 1, y2, -1, i, 0);
		a[len++] = node(x2, y2, 1, i, 0);
	}
	
	sort(a, a + len);
	for (int i = 0; i < len; i++) 
		if (a[i].pos < m)
			add(a[i].y, a[i].val);
		else
			ans[a[i].pos - m] += sum(a[i].y)*a[i].flag;

	for (int i = 0; i < p; i++)
		printf("%lld\n", ans[i]);
}

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		init();
		solve();
	}
	return 0;
}
发布了86 篇原创文章 · 获赞 8 · 访问量 2241

猜你喜欢

转载自blog.csdn.net/Fawkess/article/details/103364865