ZOJ4029 Now Loading!!! (预处理+二分)

这道题暴力没办法做,所以要从题目式子找性质,我们发现,分母的大小最多不会超过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;
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/ctyakwf/p/12627345.html
now
今日推荐