赛时
花了近2h来课这道题.
发现了贪心规律,本想着可以水水70分。
然鹅发现数据过大,似乎要打高精度?
心态崩了,最后连20分都没拿到。
后来才发现一个小小的性质,不用打高精度。
太菜了。
题解
首先我们画画柿子。
答案即为(sum_{i=l}^r a_i*2^{k_i})
其中可以控制的就是那个k数组。
考虑贪心。
我们发现,对于一个正数,当然是希望它的k值越大。
对于一个负数,当然希望它的k值越小。
那么对于每个负数,它的k值最小为1(第一个位置为0)
然后一段正数区间则是递增的。
当然,这样是错误滴。为什么呢?我们有可能把一段正数区间乘2然后合并到前面的负数,这样答案会变大。
这样一直合并合并之后,可能会出现的情况是:k数组会分成一个一个块,每块开头是1(第一块开头为0)然后向后面递增。
所以我们从左到由依次加入数字,然后把当前的数字往前面合并,如果合并到最后当前块为负数就不合并了。
但是数值要去模啊?怎么办?我们发现,负数不会特别小,最少是-2e9,那么只要正数大于4e9的时候就可以往前面疯狂合并即可。
于是我们多记录一个数值表示当前块的数值堆4e9取min即可。
拿到70分的好成绩。
对于100分呢?
我们离线询问,把询问按照有端点排序,然后依次加入数字,做与上面相同的东东。
然后由于询问的左端点不是1,那么就不能直接统计了(废话)
那么这个左端点必定把某一块分割成两个部分。
求出这一块右边部分即可。
那么问题来了:分割后两个部分右边的部分不会被合并吗?
答案是:不会。
因为我们发现,左端点所在的块右边的块的数值是小于0的(否则在做的过程中就已经合并了),我们知道,数值小于0是不能合并的,因此不会合并。
那么利用并查集维护块或是线段树即可。
标程
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cctype>
using namespace std;
const int maxn=500010;
const long long mo=1000000007;
struct node{
long long le,ri,kk,gg,lazy;
};
int n,m,l[maxn],r[maxn],gs,now;
long long a[maxn],b[maxn],c[maxn],mi[maxn],sum[maxn],jl,jr,jk,jg;
long long le[maxn],ri[maxn],k[maxn],zs[maxn],aa[maxn],qsum[maxn],col[maxn],id[maxn],wz[maxn],jll[maxn],qh[maxn],zd[maxn];
node tree[4*maxn];
void down_lazy(int x)
{
if (tree[x].lazy==1)
{
tree[x*2].le=tree[x].le;
tree[x*2+1].le=tree[x].le;
tree[x*2].ri=tree[x].ri;
tree[x*2+1].ri=tree[x].ri;
tree[x*2].kk=tree[x].kk;
tree[x*2+1].kk=tree[x].kk;
tree[x*2].lazy=tree[x].lazy;
tree[x*2+1].lazy=tree[x].lazy;
tree[x*2].gg=tree[x].gg;
tree[x*2+1].gg=tree[x].gg;
tree[x].lazy=0;
}
}
void change(int x,int l,int r,int st,int en,int le,int ri,int kk,int g)
{
if (l==st && r==en)
{
tree[x].le=le;
tree[x].ri=ri;
tree[x].kk=kk;
tree[x].gg=g;
tree[x].lazy=1;
}
else
{
down_lazy(x);
int mid=(l+r)/2;
if (mid>=en) change(x*2,l,mid,st,en,le,ri,kk,g);
else if (mid<st) change(x*2+1,mid+1,r,st,en,le,ri,kk,g);
else
{
change(x*2,l,mid,st,mid,le,ri,kk,g);
change(x*2+1,mid+1,r,mid+1,en,le,ri,kk,g);
}
}
}
void find(int x,int l,int r,int st)
{
if (l==r)
{
jl=tree[x].le;
jr=tree[x].ri;
jk=tree[x].kk;
jg=tree[x].gg;
}
else
{
down_lazy(x);
int mid=(l+r)/2;
if (mid>=st) find(x*2,l,mid,st);
else find(x*2+1,mid+1,r,st);
}
}
long long min(long long a,long long b)
{
if (a<b) return a;return b;
}
void qsort(int ll,int rr)
{
int i=ll;int j=rr;
long long m=r[(i+j)/2];
while (i<=j)
{
while (r[i]<m) i++;
while (r[j]>m) j--;
if (i<=j)
{
swap(r[i],r[j]);
swap(l[i],l[j]);
swap(wz[i],wz[j]);
i++;j--;
}
}
if (ll<j) qsort(ll,j);
if (rr>i) qsort(i,rr);
}
long long qsm(long long a,long long b)
{
long long t=1;
long long y=a;
while (b>0)
{
if ((b&1)==1) t=t*y%mo;
y=y*y%mo;
b/=2;
}
return t;
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
freopen("standard.in","r",stdin);
freopen("standard.out","w",stdout);
mi[0]=1;
for (int i=1;i<=500000;i++)
{
mi[i]=mi[i-1]*2%mo;
}
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%l64d",&a[i]);
zd[i]=(zd[i-1]+a[i]*mi[i]%mo)%mo;
}
for (int i=1;i<=m;i++)
{
scanf("%d%d",&l[i],&r[i]);
}
for (int i=1;i<=m;i++)
{
wz[i]=i;
}
qsort(1,m);
k[1]=0;le[1]=1;ri[1]=1;zs[1]=a[1];gs=1;aa[1]=a[1];qh[1]=(a[1]+mo)%mo;
change(1,1,n,le[gs],ri[gs],le[gs],ri[gs],k[gs],gs);
int op=1;
while (r[op]==1)
{
jll[wz[op]]=(qh[1]+mo)%mo;
op++;
}
for (int j=2;j<=n;j++)
{
long long zss=a[j]*2;long long aaa=a[j]*2%mo;
int kk=1;
if (a[j]>0)
{
while (gs>0 && zs[gs]+zss*mi[k[gs]]>0)
{
zss=min(5000000000,zs[gs]+zss*mi[k[gs]]);
aaa=(aa[gs]+aaa*mi[k[gs]]%mo+mo)%mo;
kk=kk+k[gs];
gs--;
}
if (gs==0)
{
gs++;
}
else
{
zss=min(5000000000,zs[gs]+zss*mi[k[gs]]);
aaa=(aa[gs]+aaa*mi[k[gs]]%mo+mo)%mo;
kk=k[gs]+kk;
}
ri[gs]=j;
k[gs]=kk;
zs[gs]=zss;
aa[gs]=aaa;
qh[gs]=(qh[gs-1]+aaa+mo)%mo;
}
else
{
gs++;
le[gs]=j;
ri[gs]=j;
zs[gs]=zss;
k[gs]=kk;
aa[gs]=aaa;
qh[gs]=(qh[gs-1]+aaa+mo)%mo;
}
change(1,1,n,le[gs],ri[gs],le[gs],ri[gs],k[gs],gs);
while (op<=m && j==r[op])
{
if (l[op]==r[op])
{
jll[wz[op]]=a[l[op]];
op++;
}
else
{
jr=0;jl=0;jk=0;jg=0;
if (l[op]>1)
{
find(1,1,n,l[op]-1);
jll[wz[op]]=(qh[gs]-qh[jg]+mo)%mo;
int opt=0;
if (jk==jr-jl+1) opt=1;
jll[wz[op]]=(jll[wz[op]]+(zd[jr]-zd[l[op]-1]+mo)%mo*qsm(mi[jr-(jk-(l[op]-jl))+opt],mo-2)%mo)%mo;
int pd=jl;
jr=0;jl=0;jk=0;jg=0;
find(1,1,n,l[op]);
if (jl!=pd)
{
jll[wz[op]]=(jll[wz[op]]-(zd[jr]-zd[jl-1]+mo)%mo*qsm(mi[jr-jk+1],mo-2)%mo)%mo;
}
op++;
}
else
{
jll[wz[op]]=(qh[gs]+mo)%mo;
op++;
}
}
}
}
for (int i=1;i<=m;i++)
{
printf("%l64d
",(jll[i]+mo)%mo);
}
}