本题乍一看好像并不会很难,思路也比较容易想到用暴力解决这道题(毕竟只是连续子序列)~~
#include<stdio.h>
int main()
{
int num[100005],i,j,n,k,sum=0,cn=0;
scanf("%d%d",&n,&k);
for(i=0;i<n;i++)
{
scanf("%d",&num[i]);
}
for(i=0;i<n;i++)
{
sum=num[i];
for(j=i+1;j<n;j++)
{
sum+=num[j];
if(sum%k==0)
{
cn++;
}
}
}
for(i=0;i<n;i++)
{
if(num[i]%k==0)
{
cn++;
}
}
printf("%d",cn);
return 0;
}
我也是直接用for循环暴力试了一下发现超时了,一般如果超时了,我们就必须优化我们的算法了
奈何学识浅薄,我未能想到如何优化,最后求助于老师才有了下面的两个算法!!!!!!!!
首先是前缀法!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
前缀法是区间问题优化的一个“利器”
#include<stdio.h>
int num[100005],sum[100005];
int main()
{
int n,t,i,j,cn=0;
scanf("%d%d",&n,&t);
num[0]=0;
for(i=1;i<=n;i++)
{
scanf("%d",&num[i]);
sum[i]=sum[i-1]+num[i];
}
for(i=1;i<=n;i++)
{
for(j=i;j<=n;j++)
{
if((sum[j]-sum[i-1])%t==0)
{
cn++;
}
}
}
printf("%d",cn);
return 0;
}
这个方法主要我们通过构建另外一个数组来存放Si 即前 i 项和,再通过Sj - Si-1 来减少运算量!!
下面还有另外一个方法(需要用到一点数学知识,较难想到)
#include<stdio.h>
int main()
{
int i,n,k,a[100005],s[100005],cnt[100];
scanf("%d%d",&n,&k);
s[0]=0;
cnt[0]=1;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
s[i]=(s[i-1]+a[i])%k;
cnt[s[i]]++;
}
long long ans=0;
for(i=0;i<k;++i)
{
ans+=(long long)cnt[i]*(cnt[i]-1)/2;
}
printf("%lld",ans);
return 0;
}
首先给出这个数学结论,即————两个数(a,b)与另外一个数(c)取模后得到相等的一个数(d)时,这两个数(a,b)的差一定是c的倍数————这样的两个数区间即k倍区间!!!!!
那么我们通过这个结论,我们便可以无需使用多重循环去枚举了
而是直接在输入数据的时候求和后直接取模,最后利用组合数进行计算即可
详情请看代码~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~