ZOJ 4029 Now Loading!!!(前缀和+二分优化)

Now Loading!!!

Time Limit: 1 Second Memory Limit: 131072 KB

DreamGrid has n integers a 1 , a 2 , , a n . DreamGrid also has n queries, and each time he would like to know the value of

1 i n a i log p a i
for a given number p, where x = max { y Z y x } .

Input

There are multiple test cases. The first line of input is an integer n indicating the number of test cases. For each test case: The first line contains two integers n and m ( 1 n , m 5 × 10 5 ) – the number of integers and the number of queries.
The second line contains n integers a 1 , a 2 , , a n ( 2 a i 10 9 ).
The third line contains m integers ( 2 p i 10 9 ).
It is guaranteed that neither the sum of all n nor the sum of all m exceeds 2 × 10 6 .

Output

For each test case, output an integer ( i = 1 m i z i ) mod 10 9 , where z i is the answer for the i-th query.

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

大致题意:给你 a n p n ,然后让你求 ( i = 1 m i j = 1 n a j log p a j ) mod 10 9 .

显然,直接计算的复杂度是O(nm)的,对于 1 n , m 5 × 10 5 的数据来说显然是会TLE的。但是我们考虑到分母 l o g p a j 的取值很少,只能是[2,30],所以可以考虑根据把分母相同的一起计算。首先,我们对 a n 进行排序,然后对于每一个给定的 p i ,根据 p i 的不同次方来统计。例如当考虑 p i j 时,我们要统计 p i k 1 < a k p i k n a k k 。由于 a n 已经排好序,所以我们可以用二分的方法确定满足条件的 a k 的范围,然后用前缀和求得区间和。

这样对于每一个 p i ,分成 l o g p i a n 个部分计算,每个部分二分出 a k 的范围再前缀和计算,总的复杂度O(m l o g p i l o g a i )。但是关于前缀和部分,要注意先求和再除以某个数字向下取整 与 先对每个数字向下取整再求和是不一样的。我们要的是后者,所以我们在预处理前缀和的时候,要根据分母的不同求多个前缀和,第i个前缀和存的是每个数字先除以i之后再求的前缀和。具体步骤见代码:

#include<bits/stdc++.h>
#define mod 1000000000
#define LL long long
#define N 500010
using namespace std;

int a[N],s[33][N],ans;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int T; cin>>T;
    while(T--)
    {
        ans=0;
        int n,m;
        cin>>n>>m;
        //memset(s,0,sizeof(s));
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n);
        for(int j=1;j<=32;j++)
            for(int i=1;i<=n;i++)
                s[j][i]=(a[i]/j+s[j][i-1])%mod;
        for(LL i=1;i<=m;i++)
        {
            LL y,x,res=0,t=0;
            cin>>y; x=y; int last=0;
            while(x/y<=a[n])
            {
                t++;
                int pos=upper_bound(a+1,a+1+n,x)-a;
                res+=(s[t][pos-1]-s[t][last]+mod)%mod; last=pos-1;
                if (x<a[n]) x*=y; else break;
            }
            ans=(ans+res%mod*i%mod)%mod;
        }
        cout<<ans<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/u013534123/article/details/80191581
now
ZOJ