p3397题解

题目链接:https://www.luogu.com.cn/problem/P3397
这是一道二维前缀和的题目
题目简述:给定一个n*n的格子,有m次输入,每次输入会给你地毯的左上角和右下角,要求输出每个格子上的地毯数量
这道题数据比较水,暴力好像也能过
暴力思路:对每一次输入fx,fy(左上角) ex,ey(右下角)

点击查看代码
for(int i=fx;i<=ex;i++)
{
  for(int j=fy;j<=ey;j++)
   {
    mp[i][j]++;
   }
}
但是这样显然不是正解,我们需要用到前缀和和差分来优化 正解代码如下:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int diff[1005][1005];
signed main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int fx,fy,ex,ey;
        cin>>fx>>fy>>ex>>ey;
        /*
         * 二维差分操作:
         * 对矩形区域 (fx,fy) → (ex,ey) 整体 +1
         */
        diff[fx][fy]++;// 矩形左上角 +1
        diff[fx][ey+1]--; // 矩形右上角外 -1
        diff[ex+1][fy]--; // 矩形左下角外 -1
        diff[ex+1][ey+1]++;// 矩形右下角外 +1(抵消两次 -1)
    }
 // 还原二维前缀和
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
           /*
             * 容斥原理:
             * 当前格子 = 上 + 左 - 左上 + 自身
             *
             * diff[i][j] 此时已经是“增量”
             * 通过累加变成真实覆盖次数
             */
            diff[i][j]+=diff[i-1][j]+diff[i][j-1]-diff[i-1][j-1];
            cout<<diff[i][j];
            if(j!=n) cout<<' ';
        }
        cout<<endl;
    }

    return 0;
}
更多关于前缀和的知识点我后面会出一篇知识点的总结,如果你还有疑问,欢迎你在评论区留下你的疑问,我会尽可能地解答^_^ 以下为更为直观的图片,希望能够帮助你更好的理解^_^

26.5.15

posted @ 2026-05-15 16:02  cjimer  阅读(1)  评论(0)    收藏  举报