luoguP3932 浮游大陆的68号岛

Date: Mon 05 November 2018
Updated: Mon 05 November 2018

In 5. OI.

Tags: OI

题目


开四个数组:

\(lcnt[i]\)记录仓库i左边(不包括i)共有多少物品 \(rcnt[i]\)记录仓库i右边(不包括i)共有多少物品 \(lcost[i]\)记录将仓库i左边的所有物品移到仓库i所需的代价 \(rcost[i]\)记录将仓库i右边的所有物品移到仓库i所需的代价。


\(lcnt[i]\)\(rcnt[i]\)很好算,考虑如何O(n)计算\(lcost[]\)\(rcost[]​\)

\(lcost[]\)为例

考虑新加入一个仓库。假设为6。

编号(i) 1 2 3 4 5 6
\(lcnt[i]\) 0 4 5 6 8 9

把1-5号仓库的所有物品移到6号仓库等价于把1-4号仓库的所有物品移到5号仓库,然后把5号仓库里的所有东西移到6号仓库。

也就是\(lcost[i]=lcost[i-1]+lcnt[i]·dis(i-1,i)\)

\(rcost[]\)也可以如法炮制


考虑对于一个询问\(l..r\)

image

一定是形如这样的(或者在x的右边;或者包括了x,包括x时可以分成两段分开计算)

\(l..r\)的所有物品移到x等价于把r左边所有物品移到r,然后把r仓库的所有东西移到x,减去把l左边所有东西移到l,然后把l仓库的所有东西移到x

也就是\(cost(l,r)=lcnt[r+1]·(po[x]-po[r])+lcost[r]-lcost[l]-lcnt[l]·(po[x]-po[l])\)

\(l..r\)在x的右边也可以如法炮制


code
#include<bits/stdc++.h>
#define ll long long
#define N 200010
#define mo 19260817
#define md(a) (((a)%mo+mo)%mo)
#define mem(a,b) memset(a,b,sizeof(a))
#define fsb(a,b,c) for(ll a=b;a<=(c);a++)
#define fbs(a,b,c) for(ll a=b;a>=(c);a--)
using namespace std;
ll n,m,po[N],a[N],lcnt[N],rcnt[N],lcost[N],rcost[N],x,l,r;
template<typename qw>inline void rll(qw &x){
 x=0;qw f=1;char c=getchar();
 while(!isdigit(c))f=c=='-'?-1:f,c=getchar();
 while(isdigit(c))x=x*10+c-'0',c=getchar();
 x*=f;
}
int main(){
// freopen("3932_1.in","r",stdin);freopen("3932.out","w",stdout);
 rll(n);rll(m);po[1]=0;
 fsb(i,2,n){
  rll(po[i]);po[i]+=po[i-1];po[i]=md(po[i]);
 }
 mem(a,0);fsb(i,1,n)rll(a[i]);
 mem(lcnt,0);mem(rcnt,0);
 fsb(i,1,n){
  lcnt[i]=lcnt[i-1]+a[i-1];lcnt[i]=md(lcnt[i]);
 }
 fbs(i,n,1){
  rcnt[i]=rcnt[i+1]+a[i+1];rcnt[i]=md(rcnt[i]);
 }
 mem(lcost,0);mem(rcost,0);
 fsb(i,2,n){
  lcost[i]=md(lcost[i-1]+lcnt[i]*(po[i]-po[i-1]));
 }
// fsb(i,1,n)printf("%10lld %lld %lld\n",i,lcnt[i],rcnt[i]);
 fbs(i,n-1,1){
  rcost[i]=md(rcost[i+1]+rcnt[i]*(po[i+1]-po[i]));
 }
 fsb(i,1,m){
  rll(x);rll(l);rll(r);
  l=l==x?l+1:l;
  r=r==x?r-1:r;
  if(l>r){
   puts("0");continue;
  }
  ll ans=0;
  if(r<x){
   ans=md(lcnt[r+1]*(po[x]-po[r])+lcost[r]-lcost[l]-lcnt[l]*(po[x]-po[l]));
  }
  if(l>x){
   ans=md(rcnt[l-1]*(po[l]-po[x])+rcost[l]-rcost[r]-rcnt[r]*(po[r]-po[x]));
  }
  if(l<x&&r>x){
   ans=md(lcnt[x]*(po[x]-po[x-1])+lcost[x-1]-lcost[l]-lcnt[l]*(po[x]-po[l]));
   ans+=md(rcnt[x]*(po[x+1]-po[x])+rcost[x+1]-rcost[r]-rcnt[r]*(po[r]-po[x]));
   ans=md(ans);
  }
  printf("%lld\n",ans);
 }
 return 0;
}

注意:数字有点大,及时%。

Social