zoukankan      html  css  js  c++  java
  • 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
    数据规模和约定
      峰值内存消耗(含虚拟机) < 256M
      CPU消耗 < 2000ms

      请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

      注意:
      main函数需要返回0;
      只使用ANSI C/ANSI C++ 标准;
      不要调用依赖于编译环境或操作系统的特殊函数。
      所有依赖的函数必须明确地在源文件中 #include <xxx>
      不能通过工程设置而省略常用头文件。

      提交程序时,注意选择所期望的语言类型和编译器类型。

    题解

    题目清晰明了,简单的,暴力枚举~~~

     1 void fun(int *a, int n, int k)
     2 {
     3     int c = 0;
     4     for(int i=0;i<n;i++){
     5         for(int j=i;j<n;j++){
     6             int sum = 0;
     7             for(int t=i;t<j;t++){
     8                 sum += a[t];
     9             }
    10             if(!(sum%k)){
    11                 c++;
    12             }
    13         }
    14     }
    15     cout<<c<<endl;
    16  } 

     或

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 
     6 using namespace std;
     7 
     8 typedef long long ll;
     9 
    10 const int MAX = 100001;
    11 
    12 int main()
    13 {
    14     int n, k;
    15     cin>>n>>k;
    16     ll a[MAX], b[MAX], s = 0;
    17     memset(a, 0, sizeof(a));
    18     memset(b, 0, sizeof(a));
    19     ll c = 0;
    20     for(int i=1;i<=n;i++){
    21         cin>>a[i];
    22         if(a[i]%k == 0)
    23             c++;
    24         s += a[i];
    25         b[i] += s;
    26     }
    27     b[0] = 0;
    28     for(ll i=0;i<n-2;i++){
    29         for(ll j=i+2;j<=n;j++){
    30             int e = abs(b[j] - b[i]);
    31             if(e%k == 0)
    32                 c++;
    33         }
    34     }
    35     cout<<c<<endl;
    36     
    37     return 0;
    38 }

    然后,超时了~~~

    题目部分数据很大,枚举的时间复杂度为o(n^3)或o(n^2),超时还是很正常的!

    在网上学习了很多篇文章之后,总算是明白了优化算法。

    现将我的理解分享给大家!

    设有一数列a,需要求的是k=2的k倍区间:

     a = [1, 2, 3, 4, 5] 

    我们可以知道

     任何区间[i, j],都可以表示为:前 j 项的和减去前 i-1 项的和,即 sum = S[j] - S[i-1] 

    如果这个区间是k倍区间,那么下列等式成立:

    1 (S[j] - S[i-1])%k == 0
    // 移项得 2 S[j]%k == S[i-1]%k

     也就是说,我们只需要求出前n项和,即:
     S[1], S[2], ..., S[n] 

    然后我们判断它们对k取模的值,

      [1, 1, 0, 0, 1] 

    此时,我们只要随意的选取模相同的区间,那么就是满足题意的区间,但是当我们的 i 取0时,会有-1出现,因为我们的公式是

      S[j]%k == S[i-1]%k 

    所以我们要在最前面添加一个值,但是又不能影响整个数列,很明显,我们要添加一个 0, 如下图:

    图不是很好看,但是大致就是这意思!!!

    换句话说,我们只需要求出相同的数的组合数就ok了。


    解 

     1 #include<iostream>
     2 #include<cstring>
     3 
     4 using namespace std;
     5 
     6 typedef long long ll;
     7 
     8 const int MAX = 100009;
     9 int n, k;
    10 ll a[MAX], s[MAX], c = 0;
    11 
    12 int main()
    13 {
    14     
    15     cin>>n>>k;
    16     memset(a, 0, sizeof(a));
    17     memset(s, 0, sizeof(a));
    18     int x = 0, y = 0;
    19     s[0] = 1;
    20     for(int i=0;i<n;i++){
    21         cin>>x;
    22         y = (y + x)%k;
    23         s[y%k]++;
    24     }
    25     for(int i=0;i<k;i++){
    26         c += (s[i]*(s[i]-1))/2;
    27     }
    28     cout<<c<<endl;
    29     return 0;
    30 }
    View Code

    此外,我还看到另一种解法,可惜有一小地方没弄明白,这里放上代码(https://www.lucien.ink/archives/63/)
     1 #include <cstdio>
     2 
     3 int tmp, sum, cnt[100007], n, k;
     4 
     5 long long ans;
     6 
     7 int main() 
     8 {
     9     scanf("%d%d", &n, &k);
    10     for (int i = 1; i <= n; i++){
    11         scanf("%d", &tmp);
    12         sum = (sum + tmp) % k;
    13         ans += cnt[sum]++;
    14     }
    15     
    16     prisntf("%lld
    ", ans + cnt[0]);
    17     return 0;
    18 }
    View Code
  • 相关阅读:
    springboot集成mockito与powermock
    不一样的go语言-玩转语法之二
    不一样的go语言-玩转语法之一
    不一样的go语言-athens源码概览
    不一样的go语言-athens私仓安装
    不一样的go语言-构建系统与构件系统
    不一样的go语言-error
    不一样的go语言-gopher
    jssip中文开发文档(完整版)
    echarts属性的设置(完整大全)
  • 原文地址:https://www.cnblogs.com/mabeyTang/p/9966772.html
Copyright © 2011-2022 走看看