标题: 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
思路: 用一个sum[i]数组辅助保存 从1到i 区间的和,
用c[i]数组保存 区间和取余k后为i的个数,
如果两个区间取余k后相同,则这两个区间中存在一个k倍区间
通过 (c[i] *(c[i]-1))/2 计算模为i 的k倍区间的个数
注意:这是别人的思路,只是加上我个人的见解,希望可以更方便理解
来自 : http://blog.csdn.net/vagebird/article/details/69775949
#include<iostream>
#define MAX 100010
using namespace std;
int a[MAX];
int sum[MAX];
int c[MAX];
int n,k;
long ans=0;
int main()
{
freopen("1.txt","r",stdin);
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
sum[i] = sum[i-1] + a[i];
//a[i] 储存数组
//sum[i] 储存从1到i的区间和
}
//思路: C[i] 记录前缀和取余K后为i的个数
//取余k后相同的两个区间 sum[i] 跟 sum[j] 则必然存在 一个区间 sum[i-j] (i>j)是k倍区间
for(int i=0;i<=n;i++){
c[sum[i]%k]++;
}
for(int i=0;i<k;i++){
ans += (c[i] *(c[i]-1))/2 ;//通过 前缀和取余K后结果相同的个数 求得 k倍区间的个数
}
cout<<ans;
return 0;
}
还有一种类似的解法,思路差不多,不过比较巧妙,是java组一个大神跟我讲的
#include<iostream>
using namespace std;
int a[100010];
int cnt[100010];
long ans=0;
int n,k;
int main(){
freopen("1.txt","r",stdin);
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
cnt[0]=1;
int sum=0;
//核心代码
for(int i=1;i<=n;i++){
sum = (sum+a[i])%k; // 前i个数的取余k的值
ans += cnt[sum]; // 每多一个 sum ,即多出了cnt[sum] 个k倍区间
cnt[sum]++; // 取余后相同的值加一
}
cout<<ans;
return 0;
}