ZOJ 4029 Now Loading!!! 思维
Now Loading!!!
好题
题意:
给出 n 个数 a[],有 m 个询问,每次询问有一个数 p,求 sum{ floor( a[i]/(ceil(log p(a[i]))) ) } 。且当前输出的答案与前面的答案相关,不能离线做。
tags:
明显只能预处理做,考虑对于一个数 p:
- 如果 1<a[i]<=p ,那么 ceil(log p(a[i])) = 1 。
- 如果 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;
}