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

Now Loading!!!

Time Limit: 1 Second      Memory Limit: 131072 KB

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

for a given number , where , .

Input

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

The first line contains two integers and () -- the number of integers and the number of queries.

The second line contains integers ().

The third line contains integers ().

It is guaranteed that neither the sum of all nor the sum of all exceeds .

Output

For each test case, output an integer , where is the answer for the -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

Author: LIN, Xi

Source: The 15th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple

思路:题意很容易看懂,但是暴力的话肯定超时。仔细看的话,可以发现因为分母是向上取整的,再根据题目给的数据范围我们可以确定分母一定在1~30之间。并且我们可以知道如果a[i]的范围在(p^(i-1),p^i]之间的话分母就为i,这样子的话先从小到大把数组排好序,之后就可以二分查找p^i(p^i<=a[n])在数组中的位置,这样子数组就能被分割成一段一段的,每一段当中的数分母都是相同的。我们通过预处理好a[i]/k(1<=i<=n,1<=k<=30)的前缀和,就能很快的计算出来了。

debug了好久才发现最后输出答案的时候要(sum+mod)%mod,sum不可能为负数不知为啥要加上mod再取模,有大佬知道吗TAT

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=500005;
const int mod=1e9;
int a[maxn],p[maxn],k[35][maxn];
int n,m;
void init()
{
    for(int i=1;i<=30;i++)
    {
        k[i][0]=0;
        for(int j=1;j<=n;j++)
        {
            k[i][j]=(k[i][j-1]+(a[j]/i))%mod;
        }
    }
}
int main()
{
    int t,flag[maxn],cnt;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        init();
        for(int i=1;i<=m;i++)
            scanf("%d",&p[i]);
        ll sum=0,ans;
        ll temp;
        for(int i=1;i<=m;i++)
        {
            temp=1;
            cnt=0;
            ans=0;
            while(temp*p[i]<=a[n])
            {
                temp*=p[i];
                int l=1,r=n;
                while(l<=r)
                {
                    int mid=(l+r)/2;
                    if(a[mid]<=temp)
                        l=mid+1;
                    else
                        r=mid-1;
                }
                flag[++cnt]=r;
            }
            if(flag[cnt]<n)
                flag[++cnt]=n;
            for(int j=1;j<=cnt;j++)
            {
                ans=(ans+(k[j][flag[j]]-k[j][flag[j-1]]))%mod;
            }
            sum=(sum+ans*i)%mod;
        }
        printf("%lld\n",(sum+mod)%mod);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值