题意:
给你长度为n的a序列
下面由m次询问,每一次询问给你一个p,让你算zi=Σ[1,n]floor(ai/ceil(logp(ai)))
在让你输出Σ[1,n]i*zi,其中要MOD(1e9)
这道题听了大佬的思路,式子中logp(ai)这一个项的数据范围不大,最多只有30,所以我们可以暴力这一部分。
需要做一系列预处理,处理出排序后b数组的原来下标的前缀和bef[],再算出每一个b[i]的幂次项,sum[i][j]=(b[i])^j
然后对于每一个a[i],我们去遍历它的分母,因为他的分母最多只有30,然后每当遍历一个分母j,a[i]/j,我们需要找出满足ceil(logp(a[i]))=j
的b[i]的下标和。这里查找就要用到二分,而二分就需要排序(这也是为什么我们需要处理出bef,因为排完序后下标是乱的,所以我们需要用bef来记录值)
这样我们只要每一次找到满足p^(j-1)<a[i]<=p^j ,p∈b[],中满足条件的那一段区间的两边的临界值,k∈[down,up],满足b[k]^(j-1)<a[i]<=b[k]^j
再让答案ans=ans+a[i]/j*(bef[up]-bef[down-1]),就可以了。
因为这里有点暴力,复杂度是O(30n*logn),常数有点大,所以要进行一定的常数剪枝
其实就是每一次遍历的边界值都严格按照当前的n,m来,不要用30,因为这个是最坏的情况的复杂度常数
还有这里要用int来开数组,long long 开的1e7的数组会MLE.
这道题卡的东西很多,空间也卡,时间也卡,,,,导致思路对的,剪枝剪到怀疑人生,要是再赛场上,肯定就挂了,,,,
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef int ll;
typedef long long int lli;
const int MAXN = 5e5 + 20;
const ll MOD = 1e9;
const ll INF = 0x3f3f3f3f;
typedef struct node
{
ll x;
ll id;
}node;
ll a[MAXN];
node b[MAXN];
ll sum[MAXN][31];
lli bef[MAXN];
ll siz[MAXN]; //记录在1e9内,b[i]幂次项的个数
int n,m;
ll bin_search1(ll x,int y)
{
ll l=1;
ll r=m;
ll now;
while(l<r)
{
ll mid=(l+r)>>1;
if(y-1>=siz[mid]) now=INF;
else now=sum[mid][y-1];
if(now<x)
l=mid+1;
else
r=mid;
}
if(y-1>=siz[l]) now=INF;
else now=sum[l][y-1];
if(now<x) return l;
else return l-1;
}
ll bin_search2(ll x,int y)
{
ll l=1;
ll r=m;
ll now;
while(l<r)
{
ll mid=(l+r)>>1;
if(y>=siz[mid]) now=INF;
else now=sum[mid][y];
if(now>=x)
r=mid;
else
l=mid+1;
}
if(y>=siz[r]) now=INF;
else now=sum[r][y];
if(now>=x)return r;
else return r+1;
}
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int maxx=0;
int minn=INF;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
maxx=max(a[i],maxx);
}
for(int i=1;i<=m;i++)
{
scanf("%d",&b[i].x);
b[i].id=(ll)i;
minn=min(minn,b[i].x);
}
sort(b+1,b+1+m,cmp);
bef[0]=0;
for(int i=1;i<=m;i++)
{
bef[i]=bef[i-1]+b[i].id;
}
for(int i=1;i<=m;i++)
{
sum[i][0]=1;
sum[i][1]=b[i].x;
int j;
int si=log10(maxx)/log10(b[i].x); //剪枝
for(j=2;j<=si+1;j++)
{
lli tmp=(lli)sum[i][j-1]*b[i].x;
if(tmp>INF)
{
sum[i][j]=INF;
j++;
break;
}
else
{
sum[i][j]=tmp;
}
}
siz[i]=j;
}
lli ans=0;
for(int i=1;i<=n;i++)
{
ll si=log10(a[i])/log10(minn); //剪枝
for(int j=1;j<=si+1;j++)
{
ll up=bin_search1(a[i],j);
ll down=bin_search2(a[i],j);
lli sum=a[i]/j;
if(up>=down)
ans=(ans+(lli)sum*(bef[up]-bef[down-1])%MOD)%MOD;
}
}
printf("%lld\n",ans);
}
return 0;
}