k倍区间 Java

相关题目:

和为K的子数组

统计【优美子数组】

题目描述
给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K倍区间。

你能求出数列中总共有多少个 K倍区间吗?

输入格式

第一行包含两个整数 N和 K。以下 N
行每行包含一个整数 Ai。

输出格式

输出一个整数,代表 K倍区间的数目。

数据范围

1≤N,K≤100000
1≤Ai≤100000

输入样例

5 2
1
2
3
4
5

输出样例:

6

思路
1.仔细读题不难发现,这就是一维前缀和问题:若给定数组L到R为的和为K的倍数,那么答案anscount++。
(如果对前缀和没啥概念,我找到了一篇前缀和讲的很好的博客,网站放这里了DWVictor——前缀和 DWVictor大佬写的,很详细,如果这样侵权了请告诉我,我删,才开始写博客有些规矩不是很清楚,有什么不对的希望大家批评指正。)
这题数据很大,硬算肯定超时,而前缀和正好是降低时间复杂度度的。
2.L到R为的和用前缀和的表示方法是sum[R]-sum[L-1],草稿纸上画一下,就能大概推出来在这里插入图片描述

3.有了以上的方法做指导,我们接下来做的就很容易了,只需要找出有多少个sum[R]-sum[L-1]%K==0就行,很容易想到的一个方法双重循环

  for(int i=1;i<=N;i++)
        for(int j=1;j<=i;j++){
    
    
           if((s[i]-s[j-1])%K==0&&s[i]-s[j-1]>0){
    
    
               
               count++;
           }

        }

但是这样时间依然会超,只能拿到部分分,原因是N<=100000,最坏的情况双重循环得执行1的10次方次,大于一个亿,所以还得优化。
4.双重循环超时,我们就得考虑一重循环,优化掉一个循环,要想优化掉一个就必须从判断条件入手,因为(sum[R]-sum[L-1])%K==0,是双重循环中最重要的代码 ,我们可以将公式变形
(sum[R]-sum[L-1])%K==0->sum[R]%K==sum[L-1]%K,从这个公式我们可以得出:对前缀和取模之后,结果相等两个前缀和就能组成一个k倍区间,意思就是说对于给定K,如果有任意两个前缀和%K,的结果相等,这时的L和R就能构成一个k倍区间;
5.我们用count数组来存放取摸后的结果,count[i]表示取摸后值为i的区间个数,我们要找的就是另一个值为i的前缀和,如果有另一个anscount++;这样就能把双重变成一重,1—N,对每一个前缀和sum[i]取摸,有相同结果的,anscount++;
6.还有一点在循环之前sum[0]%k也等于0,因此余数为0的一个前缀和已经有一个了,所以count[0]=1;
然后就是全部代码


import java.util.Scanner;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        int K=input.nextInt();
        int count[]=new int [1000001];
        int arr[]=new int[N+1];
        int s[]=new int[N+1];
        for(int i=1;i<=N;i++){
    
    
            arr[i]=input.nextInt();
            s[i]=s[i-1]+arr[i];    //计算前缀和
            s[i]%=K;      //在这里直接对前缀和取摸
        }
        count[0]=1;
        long anscount=0;  //int 会爆掉

        for(int i=1;i<=N;i++)
        {
    
    
           anscount+=count[s[i]];//除了count[0]=1,其余的初始值都为0,                 
            count[s[i]]++;       //如果出现过一次后加1,出现过两次及以上,anscount++,      
            					 //我们就是要找总共有多少对,
            					 //只出现一次虽然count[i]加1但总的答案不会加
           }
        System.out.println(anscount);
    }
}

最后还是感谢y总的指导

猜你喜欢

转载自blog.csdn.net/qq_44844588/article/details/106915847