• 前缀和小结 By cellur925


    这篇主要是来介绍前缀和的QAQ。

    前缀和有一维的和二维的,一维的很容易理解,高中数学必修5第二章数列给出了前n项和的概念,就是前缀和。一维的我们在这里简单说一句。

    一维前缀和

    预处理:在输入一个数列的时候累加

    查询区间和:查询[i,j]区间全部元素的和--sum[j]-sum[i-1]

    二维前缀和

    预处理:用到了容斥原理的知识。即求矩阵左上角的顶点与当前点所围成的矩形所覆盖的权值。

                  设f[][]为前缀和数组,则f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+a[i][j]

    (注:图片来源@ShawnZhou 神犇,原文地址,感谢,侵删。)

    查询区间和:

      对于一个边长为R的正方形,以(i,j)作为右下角的,那它矩阵中的和为

      s[i][j]-s[i-R,j]-s[i,j-R]+s[i-R,j-R]

    放两道例题跑(

    例题1 [HNOI2003]激光炸弹

    前缀和+枚举边长

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 int n,R,ans;
     5 int f[5090][5090];
     6 int main()
     7 {
     8     scanf("%d%d",&n,&R);
     9     for(int i=1;i<=n;i++)
    10     {
    11         int x=0,y=0,z=0;
    12         scanf("%d%d%d",&x,&y,&z);
    13         f[x+1][y+1]=z;
    14     } 
    15     for(int i=1;i<=5001;i++)
    16      for(int j=1;j<=5001;j++)
    17      {
    18          f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
    19      }
    20     for(int i=0;i<=5000-R;i++)
    21      for(int j=0;j<=5000-R;j++)
    22      {
    23          int tmp=f[i+R][j+R]-f[i+R][j]-f[i][j+R]+f[i][j];
    24          ans=max(tmp,ans);
    25      }
    26     printf("%d",ans);
    27     return 0;
    28 } 
    View Code

    例题2 最大正方形

    可能是隐藏在dp标签下的一个叛徒这题我觉得用前缀和最简单,而且还是01矩阵,只要预处理出前缀和然后枚举最大正方形的边长大小,再看矩阵中权值和是否等于边长*边长即可。以及注意边界问题。

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 
     6 int n,m,ans;
     7 int f[200][200];
     8 
     9 int main()
    10 {
    11     scanf("%d%d",&n,&m);
    12     for(int i=1;i<=n;i++)
    13         for(int j=1;j<=m;j++)
    14         {
    15             scanf("%d",&f[i][j]);
    16             f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
    17         }
    18     for(int i=1;i<=n;i++)
    19         for(int j=1;j<=m;j++)
    20             for(int k=1;k<=max(n,m);k++)
    21             {
    22                 if(i-k<1) continue;
    23                 if(j-k<1) continue;
    24                 int qwq=f[i][j]-f[i-k][j]-f[i][j-k]+f[i-k][j-k];
    25                 if(qwq==k*k) ans=max(ans,k);
    26             }
    27     printf("%d",ans);
    28     return 0;
    29 }
    View Code

    *update on 10-18

    noip2014无线网络发射器选址

    二维前缀和裸题,当然也可直接枚举中心统计。

    但是发现自己前缀和这理解可能有点问题hhh。

    其实是这样的qwq。(当然变量名不能用x1y1之类的啦)

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<iostream> 
     4 
     5 using namespace std;
     6 typedef long long ll;
     7 
     8 int d,n;
     9 ll tot,ans;
    10 ll w[500][500];
    11 
    12 int main()
    13 {
    14 //    freopen("1.out","w",stdout);
    15     scanf("%d%d",&d,&n);
    16     for(int i=1;i<=n;i++)
    17     {
    18         int x=0,y=0,z=0;
    19         scanf("%d%d%d",&x,&y,&z);
    20         w[x][y]=z;
    21     }
    22     for(int i=0;i<=128;i++)
    23         for(int j=0;j<=128;j++)
    24             w[i][j]+=w[i-1][j]+w[i][j-1]-w[i-1][j-1];
    25     for(int i=0;i<=128;i++)
    26         for(int j=0;j<=128;j++)
    27         {
    28             //if(i-d<0||i+d>128||j-d<0||j+d>128) continue;
    29             int tx=(i+d<=128) ? (i+d) : 128;
    30             int ty=(j+d<=128) ? (j+d) : 128;
    31             int lx=(i-d>=0) ? (i-d) : 0;
    32             int ly=(j-d>=0) ? (j-d) : 0;
    33             ll tmp=w[tx][ty]-w[tx][ly-1]-w[lx-1][ty]+w[lx-1][ly-1];
    34             //if(i==120&&j==120) cout<<tx<<" "<<ty<<" "<<lx<<" "<<ly;
    35             //if(i==120&&j==120) cout<<tmp;
    36             if(tmp>ans) ans=tmp,tot=1;
    37             else if(tmp==ans) tot++;
    38         }
    39     printf("%lld %lld",tot,ans);
    40     return 0;
    41 }
    View Code
  • 相关阅读:
    枚举
    IOS uitableview代理方法
    IOS图片拉伸模式
    IOS单例的设计模式
    圆角属性
    IOS 随机数
    IOS正则表达式
    添加 分类 自动适配图片
    用grep查找文件内容
    Openscada远程配置
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9291037.html
Copyright © 2020-2023  润新知