用前缀和来求区间和,然后用一个二重循环穷举,但是因为问题规模为100000
,所以超时(28分)
超时代码:
#include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <string.h> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map> #define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 100010 #define MAX 0x06FFFFFF #define V vector<int> #define ll long long using namespace std; ll sum[LEN]; int main(){ // freopen("D:/CbWorkspace/blue_bridge/k倍区间.txt","r",stdin); int i,j,n,k,ans=0; I("%d%d",&n,&k); FF(i,n){ I("%d",&j); sum[i+1]=sum[i]+j; } for(i=1;i<=n;i++){ for(j=i;j<=n;j++){ int t=(sum[j]-sum[i-1]); if((sum[j]-sum[i-1])%k==0) ans++; } } printf("%d\n",ans); return 0; }
观看了大佬的AC代码,终于明白怎么回事了。一句话, 计算前缀和然后取余k, 如果前i项和取余k与前j项和取余k后相同,那么i到j这个区间和为k的倍数
注意ans,cnt,sum都要开 long long
AC代码:
#include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <string.h> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map> #define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 100010 #define MAX 0x06FFFFFF #define V vector<int> #define ll long long using namespace std; ll sum[LEN]; ll cnt[LEN]; int A(int n,int m){ int a=1; while(m){ a*=n--; m--; } return a; } int C(int n,int m){ int c=A(n,m); while(m){ c/=m--; } return c; } int main(){ // freopen("D:/CbWorkspace/blue_bridge/k倍区间.txt","r",stdin); int i,j,n,k; ll ans=0; I("%d%d",&n,&k); FF(i,n){ I("%d",&j); sum[i+1]=sum[i]+j; } cnt[0]=1; F(i,1,n+1){ cnt[sum[i]%k]++; } FF(i,k){ if(cnt[i]) ans+=cnt[i]*(cnt[i]-1)/2; //C(n,2) } printf("%lld",ans); return 0; }