ZOJ 4029 Now Loading!!! 思维

Now Loading!!!

好题

题意:
给出 n 个数 a[],有 m 个询问,每次询问有一个数 p,求 sum{ floor( a[i]/(ceil(log p(a[i]))) ) } 。且当前输出的答案与前面的答案相关,不能离线做。
tags:
明显只能预处理做,考虑对于一个数 p:

  1. 如果 1<a[i]<=p ,那么 ceil(log p(a[i])) = 1 。
  2. 如果 p<a[i]<=p^2,那么 ceil(log p(a[i])) = 2 。
    ........

所以我们可以对这 n 个数预处理出 a[i]/1 的前缀和、a[i]/2 的前缀和、a[i]/3 的前缀和 .......
然后只要二分算一下就好,复杂度 O(n*30*log(n)) 。

//http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4029
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 500005, mod = 1e9;

ll n, m, a[N], p[N], sum[31][N];
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        scanf("%lld%lld", &n, &m);
        rep(i,1,n) scanf("%lld", &a[i]);
        rep(i,1,m) scanf("%lld", &p[i]);
        sort(a+1, a+1+n);
        rep(j,1,30) rep(i,1,n)
            sum[j][i] = sum[j][i-1] + a[i]/j;
        ll  ans = 0;
        rep(j,1,m) {
            ll  ans1 = 0;
            ll  pp = 1, cnt = 1;
            for(int pos=0, pos2; pp<a[n]; ++cnt) {
                pos2 = upper_bound(a+1, a+1+n, pp) - a-1;
                pp *= p[j];
                pos = upper_bound(a+1, a+1+n, pp) - a-1;
                if(a[pos]>pp) continue;
                ans1 = (ans1 + (sum[cnt][pos]-sum[cnt][pos2]))%mod;
            }
            ans = (ans + ans1*j%mod)%mod;
        }
        printf("%lld\n", (ans+mod)%mod);
    }

    return 0;
}
posted @ 2018-05-08 22:41  v9fly  阅读(433)  评论(0编辑  收藏  举报