codeforces835 C

本文介绍了一种使用二维前缀和与动态规划解决特定查询问题的方法。在一个平面直角坐标系的第一象限中,有若干整点带有权值,权值随时间变化。任务是在指定区域内查询所有点权值的总和,并考虑到权值随时间改变的情况。通过预处理二维前缀和,可以有效地降低查询的时间复杂度。
摘要由CSDN通过智能技术生成

极端不擅长DP……orz


题意大概是这样的:
在一个平面直角坐标系的第一象限中有k个整点带有权值,且权值不超过c。ts后由于发生了一些事情,权值变成了k+t,当然如果超过c就重新计算。
举个栗子:
3 4 5
1 1 2
2 3 0
3 3 1
0 1 1 100 100
1 2 2 4 4
2 2 1 4 7
1 50 50 51 51
第一行表示要输入3个点,4次查询,最大权值为5
之后的三行,表示(1,1)权值2,(2,3)权值0,(3,3)权值1
之后第一次查询,(1,1)到(100,100)权值和3,第二次查询为1s后,(3,3)查询在范围内权值变为2,(2,3)变1,则结果为3.同理,之后查询,结果分别为5、0
数据范围:点数、 查询数1 ≤ n,q ≤  105 ,权值上限 1 ≤ c ≤ 10
每个点
1 ≤ xi, yi ≤ 100, 权值0 ≤ si ≤ c ≤ 10
每次查询
0 ≤ ti ≤  109 , 1 ≤  x1i < x2i ≤ 100, 1 ≤  y1i  < y2i ≤ 100

我们的一个直观想法就是先开一个二维数组来存数然后每次查询遍历数组以求出前缀和。这样的每次查询都是 O(n2) 的,q次查询就是 qn2 ,这个复杂度是绝对吃不消的。所以我们需要提前预处理以起到最快的效果。而方法就是 二维前缀和
这玩意说实话我没有听说过。但首先各位请理解一下这个转移方程:

dp[k][i][j]=dp[k][i-1][j]+dp[k][i][j-1]-dp[k][i-1][j-1]+ kx,y

这样我们可以预处理出一个前缀和:即权值为c的点在(x,y)范围内是怎样的前缀和。或者我们也可以这样考虑:将权值作为新的一维来考虑,将每一个权值所表示的平面的每一点的权值和预处理出来。

这里写图片描述
我们要求的就相当于蓝色矩形的面积+黄色矩形的面积-绿色矩形的面积+该点的权值。

下一步就是怎么求。很容易的我们列出这样一个式子:
query(t,x1,y1,x2,y2)=kp=0((p+ti)%(c+1))(dp[k][x2][y2]dp[k][x11][y2]dp[k][x2][y11]+dp[k][x11][y11])
这样每次查询为O(cn)的,预处理则是 O(c×x2)
当然这道题挖了一个大坑:点是可以重合的,此时权值叠加取模。嗯……很坑
具体就看代码吧

#include <bits/stdc++.h>
using namespace std;
int dp[11][103][103];
int c,ans,n,q;
int query(int t,int x1,int y1,int x2,int y2){ //查询操作
    ans=0;
    int e;
    for(int i=0;i<=c;++i){
        e=(t+i)%(c+1);
        ans+=e*(dp[i][x2][y2]-dp[i][x1-1][y2]-dp[i][x2][y1-1]+dp[i][x1-1][y1-1]);
    }
    return ans;
}
void init(){        //输入并初始化dp数组
    cin>>n>>q>>c;
    int x1,y1,k;
    for(int i=0;i<n;++i){
        cin>>x1>>y1>>k;
        dp[k][x1][y1]++;
    }
    for(int i=0;i<=c;++i)
        for(int j=1;j<=101;++j)
            for(int p=1;p<=101;++p)
                dp[i][j][p]+=dp[i][j-1][p]+dp[i][j][p-1]-dp[i][j-1][p-1];
}
int main(){
    init();
    int t,x1,y1,x2,y2;
    while(q--){         //执行
        cin>>t>>x1>>y1>>x2>>y2;
        cout<<query(t,x1,y1,x2,y2)<<"\n";
    }
    return 0;
}

我真是太菜了.jpg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值