【蓝桥杯集训1】前缀和专题(4 / 5)

目录

前缀和模板

1、一维前缀和

2、二维前缀和

!3956. 截断数组 - 前缀和+枚举 

1230. K倍区间 - 前缀和 + 数学

99. 激光炸弹 - 


前缀和模板

1、一维前缀和

活动 - AcWing

import java.util.*;

class Main
{
    static int N=100010;
    static int[] a=new int[N],s=new int[N];
    
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),t=sc.nextInt();
        
        for(int i=1;i<=n;i++)
        {
            a[i]=sc.nextInt();
            s[i]=s[i-1]+a[i];
        }
        
        while(t-->0)
        {
            int l=sc.nextInt(),r=sc.nextInt();
            System.out.println(s[r]-s[l-1]);
        }
    }
}

2、二维前缀和

活动 - AcWing

import java.util.*;

class Main
{
    static int N=1010;
    static int[][] a=new int[N][N],s=new int[N][N];
    
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),m=sc.nextInt(),q=sc.nextInt();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                a[i][j]=sc.nextInt();
                s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
            }
            
        while(q-->0)
        {
            int x1=sc.nextInt(),y1=sc.nextInt(),x2=sc.nextInt(),y2=sc.nextInt();
            int res=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
            System.out.println(res);
        }
    }
}

!3956. 截断数组 - 前缀和+枚举 

3956. 截断数组 - AcWing题库

题目:

一个数组切两刀,有三段,每段总和相等,问有多少种切法?

思路:

三段相等,则每段是sum/3,记作avg

如果总和sum不是avg的倍数,则不可能被平均分为3段

剩下的情况就是必然能分成3段,每段总和相等:

我们可以枚举第二刀的位置,枚举每种第二刀位置j时,对应有cnt种第一刀的切法

res累加这些情况即可

  • 因为要分成3段,则第二刀之前至少要留2个元素给第一段和第二段,所以枚举第二段的位置i从3开始
  • 先记录第一段的和==avg的个数
  • 如果此时对应的第三段和==avg,则res累加
import java.util.*;

public class Main {
    static int N = 100010;
    static int[] s = new int[N];
    static int n,m;

    public static void main(String[] sss) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        for(int i=1;i<=n;i++) 
        {
            s[i]=sc.nextInt();
            s[i]+=s[i-1];
        }

        if(s[n]%3!=0) {
            System.out.println(0);
            return ;
        }
        
        int avg=s[n]/3;//均值
        long res=0;
        long cnt=0;//记录第一刀的位置
        for(int i=3;i<=n;i++) //只要把第一段和第三段确定下来 就完成了题目
        {
            if(s[i-2]==avg) cnt++; //满足第一段==avg的个数 也就是合法的第一刀位置的个数
            if(s[n]-s[i-1]==avg) res+=cnt; //如果第三段和==avg 说明这个第二刀可以对应之前所有出现过的合法的第一刀
        }

        System.out.println(res);
    }
}

1230. K倍区间 - 前缀和 + 数学

活动 - AcWing

题目:

思路:

  • 要求有多少个子序列之和是k的倍数
  • 则就是求满足(sum[r]-sum[l-1])%k==0的个数
  • 也就是sum[r]%k==sum[l-1]%k
  • 从前往后枚举,如果sum[i]%k=m,在i之前的sum[j]%k==m,说明(sum[i]-sum[j])%k==0,也就是aj+1……ai这一段是k倍区间,可以记入答案
  • 所以对于每一个,只要统计它前面有多少个j就可以了
  • 开一个cnt[],cnt[i]记录余数为i的前缀和有多少个
  • 特殊情况:假如某段之和本来就是k倍区间,不需要减去区间,但cnt[0]保存的是i之前余数为0的前缀和的个数,这个区间本身没有被算进去,所以初始状态下,cnt[0]应该赋值为1
import java.util.*;

class Main
{
    static int N=100010;
    static long[] s=new long[N];
    
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),k=sc.nextInt();
        long res=0;
        long[] cnt=new long[N];
        
        cnt[0]=1;
        for(int i=1;i<=n;i++) 
        {
            s[i]=sc.nextInt();
            s[i]+=s[i-1];
        }
        for(int i=1;i<=n;i++)
        {   
            res+=cnt[(int)(s[i]%k)]; //找前面有多少个余数相同的j
            cnt[(int)(s[i]%k)]++; //当前这个i需要记录
        }
        System.out.print(res);
    }
}

 

99. 激光炸弹 - 

活动 - AcWing

题目:

思路:

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值