https://www.acwing.com/problem/content/1232
一眼前缀和,但是似乎只能优化到O(N^2),1e5的数据会超时,如果在比赛中到是可以抢一些分
枚举左端点和右端点找出所有的i,j组合,判断组合是否满足%k==0
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int a[N],s[N];
int n,k,ans;
int main()
{
cin >> n >> k;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
}
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
int n=s[j]-s[i-1];
if(n%k==0)ans++;
}
}
cout << ans << endl;
return 0;
}
但是实际上从数学上 (s[j]-s[i-1])% k == 0 可以被优化成 s[j] % k == s[i] % k
当j固定时,在1 ~ j之间找到有多少个L满足(s[j] - s[i - 1]) % k == 0 这其实就是我们第二层循环的含义,我们将循环条件简单的变一下: 当j固定时,在0 ~ j - 1之间找到有多少个L满足(s[j] - s[i]) % k == 0 可转换为:s[j] % k == s[i] % k即有多少个前缀和%k余数相等
求有多少个前缀和%k的余数相等,显然我们可以在求前缀和的时候提前%k,最后再加上余数为0的个数即可
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
typedef long long ll;
int sum[N],a[N],res[N];
int n,k;
ll ans=0;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
sum[i]=(sum[i-1]+a[i])%k;
ans+=res[sum[i]];
res[sum[i]]++;
}
cout<<ans+res[0]<<endl;
return 0;
}
标签:1230,前缀,int,res,sum,ans,区间,余数 From: https://www.cnblogs.com/lxl-233/p/17143589.html