• [蓝桥杯2017初赛]k倍区间 前缀和


    题目描述

    给定一个长度为N的数列,A1, A2, ... AN。
    如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。  
    你能求出数列中总共有多少个K倍区间吗? 

    输入

    第一行包含两个整数N和K。(1 <= N, K <= 100000)  
    以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)  

    输出

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

    样例输入

    5 2
    1
    2
    3
    4
    5

    样例输出

    6


    题解:首先暴力判断一定会超时的,

    如果区间[l,r]的和(sum[r]-sum[l])%k==0,那么sum[r]%k==sum[l]%k,

    所以只要判断有几个前缀和%k的值相等,即可以判断几个区间和%k==0

    用样例举个例子:

    sum[1]%2==1       此时vis[1]==0,所以ans=ans+vis[1]=0     vis[1]=1

    sum[2]%2==1  此时vis[1]==1,所以ans+ans+vis[1]=1     vis[1]=2

    sum[3]%2==0  此时vis[0]==0,所以ans=ans+vis[0]=1           vis[0]=1

    sum[4]%2==0  此时vis[0]==1,所以ans=ans+vis[0]=2      vis[0]=2

    sum[5]%2==1  此时vis[1]==2,所以ans=ans+vis[1]=4      vis[1]=3

    这个时候ans=4,这里统计的是区间(1,n]之间的子区间和%k==0的区间个数,还要加上[1,n]之间区间和%k==0的个数(以样例为例是区间[1,3]和[1,4])

    所以ans=6

    注意ans用long long

    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<math.h>
    #include<string.h>
    #define ll long long
    using namespace  std;
    int a[100005],sum[100005],vis[100005];
    int main()
    {
        int n,k;
        cin>>n>>k;
        ll ans=0;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            sum[i]=(sum[i-1]+a[i])%k;//如果区间[l,r]的和(sum[r]-sum[l])%k==0
            ans=ans+vis[sum[i]];     //那么sum[r]%k==sum[l]%k
            vis[sum[i]]++;           //所以只要判断有几个前缀和%k的值相等,即可以判断几个区间和%k==0
        }
        cout<<ans+vis[0]<<endl;
        return 0;
    }
     
  • 相关阅读:
    【SSH 基金会】SSH框架--struts进一步的详细解释(两)
    Java多线程的~~~synchronized加入参数,以实现独立片段
    m_Orchestrate learning system---二十八、字體圖標iconfont到底是什麼
    PhpStorm函数注释的设置
    算法讲课---3、动态规划
    人这一生为什么要努力(转自知乎)
    揭开A*算法的神秘面纱
    依赖注入那些事儿
    游戏编程十年总结(下)(转)
    游戏编程十年总结(上)(转)
  • 原文地址:https://www.cnblogs.com/-citywall123/p/12337928.html
Copyright © 2020-2023  润新知