Codeforces Round #427 (Div. 2) - C
题目链接:http://codeforces.com/contest/835/problem/C
题意:在二维坐标里,有n个星星,m个询问,星星的最大亮度c。然后输入n个星星的坐标和初始亮度,对于每个询问你需要回答对于左下角(x1,y1)和右上角(x2,y2)的矩形区域中的星星中,经过t秒后亮度和是多少? 对于一个星星如果在第t秒亮度为x,那么在t+1秒亮度将变成x+1(x+1<=c时)或0(x+1>c)。
思路:由于c<=10.所以对于一个矩形区域只需要统计初始每个亮度出现的数量,假设初始亮度为i的数目有cnt[i]个,那么经过t秒后的对于总亮度的共享为 cnt[i]*(i+t)%(c+1)。 然后我们定义val[i][j][k]表示坐标(i,j)中亮度为k的有多少个,然后统计一个前缀和计算即可。 还有另外一种方法是维护10个二维树状数组,然后枚举亮度后用二维树状数组统计矩形区域的和。
注意坑点:存在多个星星在同一个位置,并且可能亮度也相同。
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<string> #include<queue> #include<vector> #include<time.h> #include<cmath> #include<set> #include<map> using namespace std; typedef long long int LL; const int MAXN = 100 + 24; const int INF = 1e9; const int mod = 1e9 + 7; int n, q, c; LL val[MAXN][MAXN][15], tmpc[15]; int main(){ #ifdef kirito freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif while (~scanf("%d%d%d", &n, &q, &c)){ memset(val, 0, sizeof(val)); for (int i = 1; i <= n; i++){ int x, y, s; scanf("%d%d%d", &x, &y, &s); val[x][y][s]++; } for (int i = 1; i <= 100; i++){ for (int j = 1; j <= 100; j++){ for (int k = 0; k <= 10; k++){ val[i][j][k] += val[i][j - 1][k]; } } } for (int i = 1; i <= q; i++){ int x1, y1, x2, y2, t; scanf("%d%d%d%d%d", &t, &x1, &y1, &x2, &y2); memset(tmpc, 0, sizeof(tmpc)); for (int j = x1; j <= x2; j++){ for (int k = 0; k <= 10; k++){ tmpc[k] += (val[j][y2][k] - val[j][y1 - 1][k]); } } LL res = 0; for (int k = 0; k <= 10; k++){ res = res + (1LL * tmpc[k] * ((k + t) % (c + 1))); } printf("%lld\n", res); } } return 0; }