2
3 2
100 1000 10000
100 10
4 5
2323 223 12312 3
1232 324 2 3 5
11366
45619
没有看题目的童鞋,请仔细看完题目再来
/*
1.先将a数组排序
2.求 a/幂 的前缀和
z就是表示对于每个p 需要求出 :每个ai/(ai的幂)的和
对于每个和zi=是a[n-1]/幂1 + a[n-2]/幂2 +...+ a[0]/幂n(幂其实就是个整数)
可能产生的式子有
a[1]/1 + a[2]/1 + a[3]/1 + a[4]/2 + a[5]/2 + a[6]/2 + a[7]/3 + a[8]/4
设sum[i][j]=a[1]/i+a[2]/i+.....a[j]/i
针对每个a数组,可以得到任意区间内的a数组整除i的总和
设p^i在a数组里的位置为k,p^(i-1)在a数组里的位置为k-1
我们可以利用区间和sum,O1快速求出k与k-1的区间内a数组整除i的总和
不需要遍历k-1~~k的a数组再求和
这里最差的可能也就是每个a[i]都有不同的幂次结果
3.二分查找k,k-1
upper_bound
lower_bound
自行百度了解一下哦~
*/
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=5e5+2;
const int mod=1e9;
long long b[33]; //两个long long 一个int才AC
long long a[maxn];//三个longlong MLT
int sum[33][maxn];//三个int SF
int t,n,m; //这个zoj有毒
int biao(long long p){
int i;
b[0]=1;
for(i=1;b[i-1]<a[n-1];i++){
b[i]=b[i-1]*p;
}
return i;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&m);
long long res=0,p;
for(int i=0;i<n;i++)scanf("%lld",&a[i]);
sort(a,a+n);
for(int i=1;i<32;i++){
for(int j=0;j<n;j++){
if(j==0)sum[i][j]=a[j]/i;
sum[i][j]=(a[j]/i+sum[i][j-1])%mod;
}
}
for(int i=1;i<=m;i++){
long long ans=0;
scanf("%lld",&p);
int k=biao(p);
//printf("k=%d\n",k);
int low=-1,up;
for(int j=1;j<k;j++){
if(b[j]<a[0])continue;
up=upper_bound(a,a+n,b[j])-a;
if(up>n)break;//剪枝防TLE
//up的前一位一定是a数组里的
//if(b[j]>=a[n-1]&&up==low)break;
//printf("up=%d low=%d\n",up,low);
if(low<0)ans=sum[j][up-1];
else {
ans+=(sum[j][up-1]-sum[j][low-1]+mod)%mod;
ans%=mod;
}
low=up;
}
res+=(i*ans)%mod;
res%=mod;
}
printf("%lld\n",res);
}
}