zcmu-1907

1907: k倍区间 
  Time Limit: 1 Sec   
  Memory Limit: 128 MB 
  
Submit: 40   Solved: 19
[ Submit][ Status][ Web Board]

Description

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

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

Input

每个数据包含多组输入数据

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

Output

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

Sample Input

5 21 2 3 4 5

Sample Output

6

解析:直接暴力n^2,超时,所以要应用另外一种做法--前缀和。

分析: 
统计前缀和 
sum[1] = a1; 
sum[2] = a1+a2; 
sum[i] = a1+a2+…+ai; 
对于任意一段区间[l,r]的和就是sum[r]-sum[l-1]. 
(sum[r]-sum[l-1])%k 保证了[l,r]这段区间要么%k等于0 要么比k小 等于0这表示了正好是k的倍数 然后通过前缀和相同的数据来判断出剩下的k的倍数:(sum[r]-sum[l-1])%k == 0.变形后就是:sum[r]%k==sum[l-1]%k .

程序分析样例: 
输入: 1 2 3 4 5 

%k后前缀和: 1 1 0 0 1

当i = 0, sum=0,bk[1]=1;
当i = 1, sum=1,bk[1]=2; //因为当bk[1]之前为1时 可得相减1-1=0为k的倍数
当i = 2, sum=1,bk[0]=1;
当i = 3, sum=2,bk[0]=2; //同上理,当0-0时还是0
当i = 4, sum=4,bk[1]=3; //之前bk[1]有2个  所以有2种-法 所以sum加上2
最后统计bk[0]有几个 sum+=bk[0]  //因为之前只考虑了相减的情况 没有考虑到本身

sum = 6;

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<map>
#include<list>
#include<algorithm>
#define SIZE 200000+5
using namespace std;

const int maxn=100000+5;
int a[maxn],cnt[maxn];

int main()
{
	int n,k;
	while(~scanf("%d%d",&n,&k))
	{
		memset(a,0,sizeof(a));
		memset(cnt,0,sizeof(cnt));
		int sum=0;
		for(int i=1; i<=n; i++)
		{
			int t;
			scanf("%d",&t);
			a[i]=(a[i-1]+t)%k;
			sum+=cnt[a[i]]++;
		}
		printf("%d\n",sum+cnt[0]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yu121380/article/details/80322587
今日推荐