前缀和算法(例题解析)

上一次比赛了解了一下前缀和算法,今天特地总结一下。
前缀和是一种预处理,让你在后面的计算中可以直接应用前面已经算出的结果。下面说几道例题,巩固一下。

一:

题目链接:子段求和
如果我们不用sum[i]保存前i项的和,那么每次查询都要遍历一遍,如果记录下来,那么后面的查询直接相减就可以了。

#include <string.h>
#include <stdio.h>
int main()

{
    long long sum[50001],N,Q,A,B,i,a[50001];
     scanf("%lld",&N);
     sum[0]=0;
     for(i=1;i<=N;i++)
        {
            scanf("%lld",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
     scanf("%lld",&Q);
     for(i=1;i<=Q;i++)
     {
         scanf("%lld %lld",&A,&B);
         printf("%lld\n",sum[A+B-1]-sum[A-1]);
     }
}

二:

题目链接:最大子矩阵
这是我们比赛中的一道题目,没有见过这种题型,所以上来就是各种循环遍历,果然超时了。
后来看师哥题解才知道原来这是经典的动态规划问题,利用二维前缀和计算。

  • dp[i][j]代表左上角是矩阵第一个元素,右下角是a[i][j](就是代码中需要输入的dp[i][j])的矩形的元素总和.
  • dp[i][j]-dp[i-x][j]-dp[i][j-y]+dp[i-x][j-y]代表以a[i][j]为矩阵右下角,大小为x*y的矩阵得元素总和。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
int  dp[1010][1010];
int main()
{
   int T,maxer,m,n,x,y,i,j;
   cin>>T;
   while(T--)
   {
       memset(dp,0,sizeof(dp));
       maxer=-1;
       cin>>m>>n>>x>>y;
       for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)
        {
            cin>>dp[i][j];
            dp[i][j]+=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1];
            if(i>=x&&j>=y)
            maxer=max(maxer,dp[i][j]-dp[i-x][j]-dp[i][j-y]+dp[i-x][j-y]);
        }
        cout<<maxer<<endl;
    }
}

三:

题目链接Color the ball

每次输入两个端点,我们把左端点的值加一,右端点右边的点的值减一,因为一个数出现的次数=以这个数为左端点的次数+这个数不是左端点的次数。左端点的值+1表示这个数是左端点,右端点右边的点的值-1代表这一段区间被这个点截断,那么这个点就不加进来了。比如说有两段区间:1到3和4到6,我们已经计算出了点3的出现次数为1,我们算4出现的次数的时候,一次是以4为起点的那个,再加上3出现的次数(为什么要加上3出现的次数呢,可以这样认为,因为我们其实是假设相邻两个数是同时出现的,如果不同时出现就会被后面的数截断)也就是1,这就是2次了,但是因为第一段区间被4截断了,所以还有减掉一次,所以就是一次了。合计合计c[i]就代表了该数字的最终出现次数。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
int c[100001];
int main()
{
    int N,A,B,i;
    while(cin>>N && N)
    {
    memset(c,0,sizeof(c));
    for(i=1;i<=N;i++)
    {
        cin>>A>>B;
        c[A]++;
        c[B+1]--;
    }
    for(i=1;i<=N;i++)
    {
        c[i]+=c[i-1];
        printf("%d%c",c[i],i==N?'\n':' ');
    }
    }
}

好吧,就先列这几道题目把,以后继续补充。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值