这道题暴力没办法做,所以要从题目式子找性质,我们发现,分母的大小最多不会超过30,而我们要求的是一个和,所以想到对分母相同的数进行前缀处理
这样求和很快,也就是说,我们进行预处理,把这些数的30个分母情况都列举一遍,而求的时候,利用二分判断分母的位置,所以在开始前先对a数组排序,就变成了一段一段求和
二分的时候一定要把左右边界想清楚,本题的左边界是0,而不是1,对于我这个二分模板来说
#include<iostream> #include<cstring> #include<cstdio> #include<map> #include<algorithm> #include<queue> #define ull unsigned long long using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=5e5+10; const int mod=1e9; int sum[N]; int f[31][N]; int a[N]; int p[N]; int cnt[N]; int n,m; void init(){ int i,j; for(i=1;i<=30;i++){ f[i][0]=0; for(j=1;j<=n;j++){ f[i][j]=(f[i][j-1]+a[j]/i)%mod; } } } int main(){ int t; cin>>t; while(t--){ cin>>n>>m; int i; for(i=1;i<=n;i++){ scanf("%d",&a[i]); } for(i=1;i<=m;i++){ scanf("%d",&p[i]); } sort(a+1,a+1+n); init(); ll sum=0; for(i=1;i<=m;i++){ ll tmp=1; int idx=0; ll ans=0; while(tmp*p[i]<=a[n]){ tmp*=p[i]; int l=0,r=n; while(l<r){ int mid=l+r+1>>1; if(a[mid]<=tmp) l=mid; else r=mid-1; } cnt[++idx]=r; } if(cnt[idx]<n){ cnt[++idx]=n; } for(int j=1;j<=idx;j++){ ans=(ans+f[j][cnt[j]]-f[j][cnt[j-1]]+mod)%mod; } sum=(sum+ans*i)%mod; } cout<<(sum+mod)%mod<<endl; } }