题目描述
给定一个长度为 N的数列, A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj之和是 K的倍数,我们就称这个区间[i,j]是 K倍区间。
你能求出数列中总共有多少个K倍区间吗?
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行包含一个整数 Ai。
输出格式
输出一个整数,代表 K倍区间的数目。
数据范围
1≤N,K≤1000001≤100000,
1≤Ai≤1000001≤100000
输入样例:
5 2
1
2
3
4
5
输出样例:
6
算法1--(暴力) O(n^2)
不能ac
long long ans = 0;
for(int i = 1;i <= N;i++){
for(int j = i;j <= N;j++)
{
if((sum[j] - sum[i-1]) % K ==0)
ans++;
}
}
cout << ans <<endl;
算法2 O(n)
C(x,2)个k倍区间(即x(x-1)/2个)
最后记得要加上即区间本身(而不是部分和)就是k倍区间的 即cnt[0]
同余定理
如果a,b除以c的余数相同,就称a,b对于除数c来说是同余的,且有a与b的差能被c整除.(a,b,c均为自然数)
suma%k=x,sumb%k=x可得(sumb-suma)%k=0
好像数组不开long long 不能ac
#include<iostream>
using namespace std;
const int N=1e5+10;
typedef long long LL;
LL cnt[N];
int main()
{
int n,k;
cin>>n>>k;
LL res=0,sum=0;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
sum+=x;
cnt[sum%k]++;
}
for(int i=0;i<k;i++) //取模后最大值为k
{
res+=cnt[i]*(cnt[i]-1)/2;//任意挑两个区间可产生一个k倍区间
}
cout<<res+cnt[0];
return 0;
}
cnt[0]=1
cnt[0]存的是sum[]中等于0的数的个数,由于sum[0] = 0,所以最初等于0的有1个数
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=(sum[i-1]+a[i])%k;
}
LL ans=0;
cnt[0]=1;
for(int i=1;i<=n;i++)
{
ans+=cnt[sum[i]];//记录余数相同的个数
cnt[sum[i]]++;
}
cout<<ans;
/***
* .--, .--,
* ( ( \.---./ ) )
* '.__/o o\__.'
* {= ^ =}
* > - <
* / \
* // \\
* //| . |\\
* "'\ /'"_.-~^`'-.
* \ _ /--' `
* ___)( )(___
* (((__) (__)))
*/