Description
给出 a1,...,an a 1 , . . . , a n 和 p1,...,pm p 1 , . . . , p m ,求 ∑i=1mi⋅∑j=1n⌊aj⌈logpiaj⌉⌋ ∑ i = 1 m i ⋅ ∑ j = 1 n ⌊ a j ⌈ l o g p i a j ⌉ ⌋
Input
第一行一整数 T T 表示用例组数,每组用例首先输入两个整数,之后输入 n n 个整数和 m m 个整数 (1≤n,m≤5⋅105,2≤ai,pi≤109) ( 1 ≤ n , m ≤ 5 ⋅ 10 5 , 2 ≤ a i , p i ≤ 10 9 )
Output
输出一个整数表示结果,答案模 109 10 9
Sample Input
2
3 2
100 1000 10000
100 10
4 5
2323 223 12312 3
1232 324 2 3 5
Sample Output
11366
45619
Solution
考虑每个 aj a j 对答案的贡献,由于 ⌈logpiaj⌉ ⌈ l o g p i a j ⌉ 的取值必然介于 [1,31] [ 1 , 31 ] 之间,在把 pi p i 从小到大排完序后,这 m m 个数会被分成不超过段,其中每段的 ⌈logpiaj⌉ ⌈ l o g p i a j ⌉ 取值相同,只要维护一个 pi p i 下标的前缀和就可以 O(31) O ( 31 ) 的计算 aj a j 对答案的贡献,分段需要二分 ⌈logpiaj⌉ ⌈ l o g p i a j ⌉ 的取值
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=500005;
int T,n,m,a[maxn];
ll sum[maxn];
#define val first
#define id second
#define mod 1000000000
P p[maxn];
ll Pow(ll a,int b)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
int find(int x,int j,int r)//p^j>=x的最小j
{
int l=1,ans=-1,mid;
while(l<=r)
{
mid=(l+r)/2;
if(Pow(p[mid].val,j)>=x)ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)scanf("%d",&p[i].val),p[i].id=i;
sort(p+1,p+m+1);
sum[0]=0;
for(int i=1;i<=m;i++)sum[i]=p[i].id+sum[i-1];
ll ans=0;
for(int i=1;i<=n;i++)
{
int num=0;
ll temp=1;
while(1)
{
if((ll)temp*p[m].val<a[i])temp*=p[m].val;
else break;
}
int pre=m;
for(int j=num;j<=31;j++)
{
int pos=find(a[i],j,pre);
if(pos!=-1)
{
ans+=(ll)(sum[pre]-sum[pos-1])*(a[i]/j)%mod;
if(ans>=mod)ans-=mod;
pre=pos-1;
}
if(pre==0)break;
}
}
printf("%lld\n",ans);
}
return 0;
}