思路:
先预处理所有的ai/i的前缀和情况,因为i最多是30,(p^i = ai,i在10^9内,所以可以确定i的边界),
然后对每个pi处理,将所有的求出ai<pi^i的i,可以用二分求解。
每次求出pi对应的sum,再求出zi。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 5e5+10;
const int N = 33;
typedef long long LL;
const int MOD = 1e9;
int n,m;
int k[N][maxn]={0},a[maxn],p[maxn];
int pos[maxn];
void Init(){//预处理求前缀和
int i,j;
for(i=1;i<=30;i++){
k[i][0] = 0;
for(j=1;j<=n;j++){
k[i][j] = (k[i][j-1]+(a[j]/i))%MOD;
}
}
}
int main(void)
{
int T,i,j;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) scanf("%d",&a[i]);
for(i=1;i<=m;i++) scanf("%d",&p[i]);
sort(a+1,a+n+1);
Init();
LL sum,tmp,ans = 0;
for(i=1;i<=m;i++){
tmp = 1;
sum = 0;
int cnt = 0;
while(tmp*p[i]<=a[n]){
tmp*=p[i];
int l = 1,r = n;
while(l<=r){//二分处理pi的cnt次方
int mid = (l+r)/2;
if(a[mid]<=tmp) l = mid+1;
else r = mid-1;
}
pos[++cnt] = r;
}
if(pos[cnt]<n) pos[++cnt] = n;
for(j=1;j<=cnt;j++){
sum = (sum+k[j][pos[j]]-k[j][pos[j-1]])%MOD;
}
ans = (ans+sum*i)%MOD; //求出最终结果
}
printf("%lld\n",(ans+MOD)%MOD);
}
return 0;
}