CF-835C Star sky (前缀和)

题意:天上有很多星星,每个星星有他自己的坐标和初始亮度
每个星星的亮度在一秒内会加一如果大于最大亮度C就会变为0
观察星星,给出视野范围(矩形)的左下角和右上角,以及观察的时间
问视野中星星亮度总和是多少
思路:一开始看到这道题,二维区间,想到了线段树....(不要问我为什么想到这个
我们知道星星的亮度是在发生变化的,所以我们需要一个时间t去记录星星亮度的状态
同时利用二维前缀和的性质求矩形区间的和。同时由于不需要更新数组所以直接预处理前缀和
用sum[i][j][k] 表示左下角 (0,0)到右上角(i,j)统计亮度为k的星星的个数
由容斥可以得到(或者差分性质) sum[i][j][k] = sum[i-1][j][k] +sum[i][j-1][k] -sum[i-1][j-1][k];
(是不是有点像dp..) 在询问的时候我们就遍历所问区间中从1~c的所有亮度的总和,对其求和即为答案

完整代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const  int maxn = 105;
int n,m,c;
int sum[maxn][maxn][15];
void init(){
    for(int i = 1; i <= 100; i++){
        for(int j = 1; j <= 100; j++){
            for(int k = 0; k <= c; k++){
                sum[i][j][k] += sum[i-1][j][k] + sum[i][j-1][k] - sum[i-1][j-1][k];
            }
        }
    }

}
int main(){
    while(cin>>n>>m>>c){
        memset(sum,0,sizeof(sum));
        for(int i = 0;i<n;i++){
            int x,y,z;
            cin>>x>>y>>z;
            sum[x][y][z]++;
        }
        init();
        for(int i = 0;i<m;i++){
            int t,x1,x2,y1,y2;
            int ans = 0;
            cin>>t>>x1>>y1>>x2>>y2;
            for(int k = 0;k<=c;k++){
                //注意边界
                int num = sum[x2][y2][k]-sum[x1-1][y2][k]-sum[x2][y1-1][k]+sum[x1-1][y1-1][k];
                ans += ((k+t)%(c+1))*num;
            }
            cout<<ans<<endl;
        }
        
    }
}
原文地址:https://www.cnblogs.com/Tianwell/p/11347643.html