題意:給定一個序列,屢次詢問數組
將a數組從小到大排序,下面那個值只有不超過32種,因而預處理f[i][j],表示分母爲i時,aj/i的前綴和是多少。spa
而後對於一個給定的p,必定將分母劃分紅了一些連續的段落,經過枚舉這些分母,二分得到分母變化的位置,將區間和累計進答案。blog
注意,對於給定的p,一個分母控制的某段區間是a的元素屬於p^i+1到p^(i+1)的這段。排序
複雜度log^2n。get
#include<cstdio> //#include<cmath> #include<algorithm> using namespace std; int f,cc; void R(int &x){ cc=0;f=1; for(;cc<'0'||cc>'9';cc=getchar())if(cc=='-')f=-1; for(x=0;cc>='0'&&cc<='9';cc=getchar())(x*=10)+=(cc-'0'); x*=f; } #define MOD 1000000000 typedef long long ll; int T,n,m,a[35][500005]; ll c[500005]; //int poses[100005][35]; //double Log(const int &p,const int &x){ // return log((double)x)/log((double)p); //} int main(){ R(T); for(;T;--T){ R(n); R(m); for(int i=1;i<=n;++i){ R(a[1][i]); } sort(a[1]+1,a[1]+n+1); for(int i=1;i<=n;++i){ c[i]=(ll)a[1][i]; } for(int i=1;i<=n;++i){ for(int j=2;j<=32;++j){ a[j][i]=a[1][i]/j; } } for(int i=1;i<=32;++i){ for(int j=1;j<=n;++j){ a[i][j]=(a[i][j]+a[i][j-1])%MOD; } } // for(int p=2;p*p<=MOD;++p){ // for(int i=1;i<=32;++i){ // if((int)(ceil(Log(p,c[n]))+0.5)<i){ // poses[p][i]=n+1; // continue; // } // int l=1,r=n; // while(l<r){ // int mid=(l+r>>1); // if((int)(ceil(Log(p,c[mid]))+0.5)>=i){ // r=mid; // } // else{ // l=mid+1; // } // } // poses[p][i]=l; // } // } int p; ll ans=0; int popo[35]; for(int zu=1;zu<=m;++zu){ R(p); // if((ll)p*(ll)p<=(ll)MOD){ // for(int i=1;i<32;++i){ // if(poses[p][i]>n){ // break; // } // ans=(ans+((ll)zu*(ll)((a[i][poses[p][i+1]-1]-a[i][poses[p][i]-1]+MOD)%MOD))%(ll)MOD)%(ll)MOD; // } // } // else{ ll pp=1; for(int i=1;i<32;++i){ ll* be=upper_bound(c+1,c+n+1,pp); if(be-c>n){ break; } pp*=(ll)p; ans=(ans+((ll)zu*(ll)((a[i][upper_bound(c+1,c+n+1,pp)-c-1]-a[i][be-c-1]+MOD)%MOD))%(ll)MOD)%(ll)MOD; } // } } printf("%lld\n",ans); } return 0; }