2018ACM浙江省賽 ZOJ 4029 Now Loading!!!(前綴和+二分)

題目描述:

DreamGrid has nn integers a1,a2,,ana_1,a_2,\dots,a_n. DreamGrid also has mm queries, and each time he would like to know the value of 1inailogpai\sum\limits_{1 \le i \le n}\Bigl\lfloor \frac{a_i}{\lceil\log_{p}a_i\rceil}\Bigr\rfloor for a given number pp, where x=max{yZyx}\lfloor x \rfloor = \max\{y \in \mathbb{Z} \mid y \le x\}, x=min{yZyx}\lceil x \rceil = \min\{y \in \mathbb{Z} \mid y \ge x\}.

Input

There are multiple test cases. The first line of input is an integer TT indicating the number of test cases. For each test case:

The first line contains two integers nn and mm (1n,m5×1051 \le n, m \le 5 \times 10^5) – the number of integers and the number of queries.

The second line contains nn integers a1,a2,,ana_1, a_2, \dots, a_n (2ai1092 \le a_i \le 10^{9}).

The third line contains mm integers p1,p2,,pmp_1, p_2, \dots, p_m (2pi1092 \le p_i \le 10^{9}).

It is guaranteed that neither the sum of all nn nor the sum of all mm exceeds 2×1062 \times 10^6.

Output

For each test case, output an integer (i=1mizi)mod109(\sum\limits_{i=1}^{m} i \cdot z_i) \bmod 10^9, where ziz_i is the answer for the ii-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

翻譯:

輸入n和m,數組的長度爲n,第二行的n個數表示a數組,接下來輸入m個p,
對於每一個p,遍歷a數組,求得ZiZ_i

1inailogpai\sum\limits_{1 \le i \le n}\Bigl\lfloor \frac{a_i}{\lceil\log_{p}a_i\rceil}\Bigr\rfloor
可以得到m個這樣的數ZiZ_i

輸出的結果: (i=1mizi)mod109(\sum\limits_{i=1}^{m} i \cdot z_i) \bmod 10^9

分析:

分母的取值範圍:
每一個aia_i的範圍爲[2,109][2,10^9],每一個p的範圍爲[2,109][2,10^9]
對於分母:logpai{\lceil\log_{p}a_i\rceil}
int的範圍爲231-1(即2147483647)

分母的範圍可以最小爲1,31可以爲上限

枚舉每一個分母的值,對:
ailogpai \frac{a_i}{\lceil\log_{p}a_i\rceil} 進行前綴和

           for(int k=1; k<=30; k++)///枚舉分母
            for(int i=1; i<=n; i++)
                sum[i][k]=sum[i-1][k]+a[i]/k;

輸入每一個p,求的一個ZiZ_i:

p和每一個aia_i的大小密不可分,並且有向上取整,對a數組從小到大排序,可以用二分解決

初始化兩個值 s1=p,s2=1和index=1;
從index=1枚舉分母,通過二分找到對應的區間,記錄結果,更新s1和s2

        for(int i=1; i<=m; i++)
        {
            LL ans=0,p;
            cin>>p;
            LL s1=p,s2=1;
            int index=1;
            while(true)
            {
                int pos1=upper_bound(a+1,a+1+n,s1)-(a+1);///upper找到第一個大於s1的下標,減去a+1,相當於又減去1,例如 2 3 4 5 upper_bound(3)返回的是位置3,但pos1=2
                int pos2=upper_bound(a+1,a+1+n,s2)-(a+1);
                ans+=sum[pos1][index]-sum[pos2][index];///[pos2,pos1]這個區間的分母都爲index
                index++;
                s2=s1;
                s1*=p;///分母爲1找完了,再找分母爲2,分母爲3,,
                if(pos1==n)
                    break;
            }
            res=(res+ans*i)%mod;
        }

完整代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int mod=1e9;
const int N=5*1e5+10;
int t,n,m;
LL a[N],sum[N][35];
int main()
{
    cin>>t;
    while (t--)
    {
        cin>>n>>m;
        for (int i=1; i<=n; i++)
            cin>>a[i];
        sort(a+1,a+n+1);
        for(int k=1; k<=30; k++)///枚舉分母
            for(int i=1; i<=n; i++)
                sum[i][k]=sum[i-1][k]+a[i]/k;
        LL res=0;
        for(int i=1; i<=m; i++)
        {
            LL ans=0,p;
            cin>>p;
            LL s1=p,s2=1;
            int index=1;
            while(true)
            {
                int pos1=upper_bound(a+1,a+1+n,s1)-(a+1);
                int pos2=upper_bound(a+1,a+1+n,s2)-(a+1);
                ans+=sum[pos1][index]-sum[pos2][index];
                index++;
                s2=s1;
                s1*=p;
                if(pos1==n)
                    break;
            }
            res=(res+ans*i)%mod;
        }
        cout<<res<<endl;
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章