zoukankan      html  css  js  c++  java
  • [蓝桥杯][2017年第八届真题]k倍区间

    暴力的做法是(O(n^2)),枚举左右端点(l)(r),通过前缀和计算出(sum[l sim r] = sum[r] - sum[l-1]),但不足以通过此题。

    题意可转化为:找两个端点(l)(r),使得(sum[l sim r]\%k = (sum[r] - sum[l-1])\%k == 0),即(sum[r] equiv sum[l-1] mod k)

    于是我们统计出所有(sum[i] mod k)的余数,记为(cnt[sum[i]\%k])

    最后枚举余数((0 sim k-1)),假设当前枚举的余数为(m),则满足(sum[l sim r]\%k == m)(l)(r)配对的个数为(C_{cnt[m]}^2)

    注意点

    由于(sum[0]=0),因此初始时(cnt[0]=1)

    const int N=1e5+10;
    LL sum[N],cnt[N];
    int n,k;
    
    int main()
    {
        cin>>n>>k;
    
        cnt[0]=1;
        for(int i=1;i<=n;i++)
        {
            cin>>sum[i];
            sum[i]+=sum[i-1];
            cnt[sum[i]%k]++;
        }
    
        LL ans=0;
        for(int i=0;i<k;i++)
        {
            ans+=cnt[i]*(cnt[i]-1)/2;
        }
            
        cout<<ans<<endl;
    
        //system("pause");
        return 0;
    }
    

    也可以采用下面更简洁的写法,不再是求组合数了,而是规定了一个顺序,每次求当前为右端点(r)的情况下,(1 sim i-1)中与(sum[r])同余模(k)的左端点(l)的个数。

    const int N=1e5+10;
    int sum[N],cnt[N];
    int n,k;
    
    int main()
    {
        cin>>n>>k;
    
        LL ans=0;
        cnt[0]=1;
        for(int i=1;i<=n;i++)
        {
            cin>>sum[i];
            sum[i]=(sum[i]+sum[i-1])%k;
            ans+=cnt[sum[i]];
            cnt[sum[i]]++;
        }
        cout<<ans<<endl;
    
        //system("pause");
        return 0;
    }
    
  • 相关阅读:
    mongo的常用操作——增删改查
    配置我的sublime
    mongo概念
    mongo命令
    mongo安装与配置
    node搭建http基本套路
    模块的导出入
    vue数据绑定原理
    webpack打包速度优化
    工作中的优化之数字键盘优化
  • 原文地址:https://www.cnblogs.com/fxh0707/p/14561496.html
Copyright © 2011-2022 走看看