Now Loading!!!
题目大意:对于每次问询求那个公式的结果,最后输出每次问询*第几次的和。
记得之前组队训练时遇到过一次,当时同队的学姐提出了log的预处理,我想到了log的范围只有1~30,但是没再想下去。
顺着上面的想法,我们就会想到预处理出a数组在每个log情况下的前缀和。
对于每次问询,处理p的每个次方段里的a数组,每段里分母一样,通过二分得到第一个大于p的i次方的值,继而可以通过已经与处理好的前缀和得到这一段的所求和。
累加处理每次问询得到答案。
//ZOJ4029
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=5e5+10;
const long long mod=1e9;
int n,m;
long long a[maxn];
long long p;
long long sum[31][maxn];
long long ans;
void pre()
{
for(int k=1;k<=30;++k){
for(int i=1;i<=n;++i){
sum[k][i]=(sum[k][i-1]+1ll*a[i]/k)%mod;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
sort(a+1,a+n+1);
pre();//预处理~!
for(int i=1;i<=m;++i){
scanf("%lld",&p);
int l=1,r,k=1;
long long temp=0,x=p; //注意暂存结果longlong!
while(l<=n){
while(x<a[l]){
x*=p;k++;
}//分母一样的一起搞/xyx
r=upper_bound(a+1,a+n+1,x)-a;
temp=(temp+(sum[k][r-1]-sum[k][l-1]+mod))%mod;//+mod以防负数
l=r;
}
ans=(ans+i*temp)%mod;
}
printf("%lld\n",ans);
}
return 0;
}