暴力模拟 双循环肯定超时了,需要找到数字间的规律进行优化
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 100005
//sum[r] - sum[l-1]就是区间[l,r]的和。区间[l,r]的和是k的倍数即(sum[r] - sum[l-1])%k == 0 即sum[r]%k == sum[l-1]%k
int main()
{
ll sum[maxn]={0};
int n,k,num[maxn]={0};
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>num[i];
sum[i]=sum[i-1]+num[i];
}
//for(int i=1;i<=n;i++)cout<<sum[i]<<" ";
int cnt=0;
for(int i=0;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if( (sum[j]-sum[i])%k==0 )cnt++;//暴力枚举
}
}
cout<<cnt<<endl;
return 0;
}
改进: 利用结论
sum[r]%k == sum[l-1]%k
我们只需要记录每个sum%k=x, 并记录x的个数, 像动态规划一样遍历更新就好了。
每次都按照sum[i]%k=xi的结果,cnt[xi]的个数就是以num[i]为结尾的连续序列的个数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 100005
//sum[r] - sum[l-1]就是区间[l,r]的和。区间[l,r]的和是k的倍数即(sum[r] - sum[l-1])%k == 0 即sum[r]%k == sum[l-1]%k
int main()
{
ll sum[maxn]={0};
int n,k={0};//cnt[i]=
cin>>n>>k;
for(int i=1;i<=n;i++)
{
int temp;
cin>>temp;
sum[i]=sum[i-1]+temp;//求出前缀和
}
//for(int i=1;i<=n;i++)cout<<sum[i]<<" ";
int ans=0,cnt[maxn]={0},smk[maxn]={0};//smk[i]= sum[i] mod k
for(int i=1;i<=n;i++)
{
smk[i]=sum[i]%k;//相当于sum[i]%k=x
ans+=cnt[smk[i]];
cnt[smk[i]]++;
}
cout<<ans+cnt[0]<<endl;
return 0;
}