Codeforces Round #427 (Div. 2)

题目链接: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
", res);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kirito520/p/7271376.html