zoukankan      html  css  js  c++  java
  • 【纪中模拟2019.08.01】【JZOJ2644】数列

    题目链接

    题意:

      在一个长度为$N$的正整数序列${a_i}$中,定义一个“合法”的子区间,其和能够被$K$整除。求原序列包括多少个“合法”的子区间?

      共$T$组数据。

      $1le Tle 20,quad 1le Nle 5*10^4,quad 1le K le 10^6,quad 1le a_ile 10^9$

    分析:

      乍一看想不到$O(n\,logn)$的做法,先写一写$O(n)sim O(n^2)$的暴力吧。

      这里$O(n)$是预处理前缀和的时间,$O(n^2)$是枚举区间端点的时间。每次发现一个“合法”的子区间就$ans++$。

      思考一下,我们这么做是基于这样一个式子:$$pre[r]-pre[l-1]=sumlimits^{r}_{i=l}a_iequiv 0;(mod\,K)$$

      那么将它改写一下,显然有$$pre[r]equiv pre[l-1];(mod\,K)$$

      垂死病中惊坐起,此题开桶我看行!前缀和模$K$同余的任意两个位置作为端点所组成的区间都是“合法”的,于是我们开桶对模$K$各个余数进行计数,运用组合数求答案。

      时间复杂度O(K),空间复杂度O(N+K)。

    实现(100分):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define IL inline
    using namespace std;
    const int N=5e4;
    const int K=1e6;
    typedef long long LL;
    
        int n,T;
        LL k,a[N+3],s[N+3],c[N+3],ans;
        int cnt[K+3];
    
    int main(){
        c[0]=c[1]=0;    c[2]=1;
        for(int i=3;i<=N;i++)
            c[i]=c[i-1]+i-1;
    
        scanf("%d",&T);
        while(T--){
            scanf("%lld%d",&k,&n);
            for(int i=1;i<=n;i++)
                scanf("%lld",&a[i]);
            
            memset(cnt,0,sizeof cnt);
            s[0]=0;    cnt[0]=1;
            for(int i=1;i<=n;i++){
                s[i]=(s[i-1]+a[i])%k;
                cnt[s[i]]++;
                
            }
            
            ans=0;
            for(int i=0;i<k;i++)
                ans+=c[cnt[i]];
            
            printf("%lld
    ",ans);
            
        }
    
        return 0;
    
    }
    View Code

    小结:

      对于计数问题,我们通常可以把原理式进行变形,找到规律,就可以从暴力$ans++$进化了。

  • 相关阅读:
    linux 下安装mongodb
    python 多线程, 多进程, 协程
    5.rabbitmq 主题
    4.rabbitmq 路由
    e.target与e.currentTarget对比
    使用ffmpeg下载m3u8流媒体
    本机添加多个git仓库账号
    IE hack 条件语句
    IE8 兼容 getElementsByClassName
    IE 下 log 调试的一点不同
  • 原文地址:https://www.cnblogs.com/Hansue/p/11310258.html
Copyright © 2011-2022 走看看