洛谷P3932浮游大陆的68号岛
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷P3932浮游大陆的68号岛相关的知识,希望对你有一定的参考价值。
题目背景
大样例下发链接: https://pan.baidu.com/s/1nuVpRS1 密码: sfxg
浮游大陆的68号岛,位于浮游大陆的边境地带。平时很少有人造访。
岛上被浓厚的森林覆盖。
在这座边境地区不起眼的浮游岛上,建立着神秘的”兵器“管理仓库——妖精仓库。
题目描述
妖精仓库里生活着黄金妖精们,她们过着快乐,却随时准备着迎接死亡的生活。
换用更高尚的说法,是随时准备着为这个无药可救的世界献身。
然而孩子们的生活却总是无忧无虑的,幼体的黄金妖精们过着天真烂漫的生活,自然也无暇考虑什么拯救世界之类的重任。
有一天小妖精们又在做游戏。这个游戏是这样的。
妖精仓库的储物点可以看做在一个数轴上。每一个储物点会有一些东西,同时他们之间存在距离。
每次他们会选出一个小妖精,然后剩下的人找到区间[l,r][l,r]储物点的所有东西,清点完毕之后问她,把这个区间内所有储物点的东西运到另外一个仓库的代价是多少?
比如储物点i有x个东西,要运到储物点j,代价为
$x \times \mathrm{dist}( i , j )$
dist就是仓库间的距离。
当然啦,由于小妖精们不会算很大的数字,因此您的答案需要对19260817取模。
输入输出格式
输入格式:
第一行两个数表示n,mn,m
第二行n-1n?1个数,第ii个数表示第ii个储物点与第i+1i+1个储物点的距离
第三行nn个数,表示每个储物点的东西个数
之后mm行每行三个数x l r
表示查询要把区间[l,r][l,r]储物点的物品全部运到储物点x的花费
输出格式:
对于每个询问输出一个数表示答案
输入输出样例
5 5 2 3 4 5 1 2 3 4 5 1 1 5 3 1 5 2 3 3 3 3 3 1 5 5
125 72 9 0 70
说明
对于30%的数据,n , m \le 1000n,m≤1000
对于另外20%的数据,所有储物点间的距离都为1
对于另外20%的数据,所有储物点的物品数都为1
对于100%的数据 ,n , m \le 200000 ; a_i , b_i <= 2\cdot 10^9n,m≤200000;a i ? ,b i ? <=2?10 9
分析
我在考试的时候画呀画有时没有画出来,到最后写了一个线段树卡过去了。看题解才知道这题正解是前缀和。╮( ̄▽ ̄")╭还是本蒟蒻数学功底太差了,没有向数学模型去转化......
代码
正解:
我要说一句 C++ mod自带大常数,在保证答案正确的情况下能少用就少用吧。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn=200000+5; const ll mod=19260817; template<class T> inline void read(T &x){ x=0; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();} } int n,m; ll sum1[maxn],sum2[maxn],dis[maxn]; int main(){ read(n);read(m); for(int i=2;i<=n;++i) { read(dis[i]); dis[i]=(dis[i]+dis[i-1])%mod; } for(int i=1;i<=n;++i){ ll x;read(x); sum1[i]=(sum1[i-1]+x*dis[i])%mod; sum2[i]=(sum2[i-1]+x)%mod; } int x,l,r; ll ans; for(int i=1;i<=m;++i){ read(x);read(l);read(r); if(l>=x){ ans=(sum1[r]-sum1[l-1]+mod)%mod; ans=(ans-((sum2[r]-sum2[l-1]+mod)*dis[x])%mod+mod)%mod; }else if(x>=r){ ans=((sum2[r]-sum2[l-1]+mod)*dis[x])%mod; ans=(ans-(sum1[r]-sum1[l-1])+mod)%mod; }else if(x>l&&x<r){ ans=((sum2[x-1]-sum2[l-1]+mod)*dis[x])%mod; ans=(ans-(sum1[x-1]-sum1[l-1])+mod)%mod; ans=(ans+sum1[r]-sum1[x]+mod)%mod; ans=(ans-((sum2[r]-sum2[x]+mod)*dis[x])%mod+mod)%mod; } printf("%lld\n",ans); } return 0; }
线段树
这是一种离线的做法,先与处理出来所有点都移动到第一个点,处理目标点为1的答案,然后将目标点向右移,关系式应该很好推。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define lson now<<1,l,mid #define rson now<<1|1,mid+1,r using namespace std; typedef long long ll; const int maxn=200000+5; const ll mod=19260817; template<class T> inline void read(T &x){ x=0; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} } int n,m; ll dis[maxn],num[maxn],ans[maxn],tmp[maxn],s[maxn],c[maxn]; ll sum[maxn<<2],tag[maxn<<2],sum2[maxn<<2]; struct ask{ int x,l,r,id; bool operator < (const ask &j) const{ return x==j.x? r<j.r:x<j.x; } }q[maxn]; inline void pushup(int now){ sum[now]=(sum[now<<1]+sum[now<<1|1])%mod; sum2[now]=(sum2[now<<1]+sum2[now<<1|1])%mod; } inline void pushdown(int now){ if(!tag[now]) return; int lc=now<<1,rc=now<<1|1; sum[lc]=(sum[lc]+tag[now]*sum2[lc])%mod; sum[rc]=(sum[rc]+tag[now]*sum2[rc])%mod; tag[lc]=(tag[lc]+tag[now])%mod; tag[rc]=(tag[rc]+tag[now])%mod; tag[now]=0; } void bt(int now,int l,int r){ if(l==r){ sum[now]=tmp[l]%mod; sum2[now]=num[l]%mod; return; } int mid=(l+r)>>1; bt(lson); bt(rson); pushup(now); } void update(int now,int l,int r,int x,int y,int k){ if(x<=l&&r<=y){ sum[now]=(sum[now]+k*sum2[now])%mod; tag[now]=(tag[now]+k)%mod; return; } pushdown(now); int mid=(l+r)>>1; if(x<=mid) update(lson,x,y,k); if(y>mid) update(rson,x,y,k); pushup(now); } ll query(int now,int l,int r,int x,int y){ if(x<=l&&r<=y) return sum[now]; pushdown(now); ll res=0; int mid=(l+r)>>1; if(x<=mid) res+=query(lson,x,y); if(y>mid) res=(res+query(rson,x,y))%mod; return res; } int main(){ read(n);read(m); for(int i=2;i<=n;++i){ read(dis[i]); dis[i]=(dis[i]+dis[i-1])%mod; } for(int i=1;i<=n;++i) read(num[i]); for(int i=1;i<=m;++i){ read(q[i].x);read(q[i].l);read(q[i].r); q[i].id=i; } sort(q+1,q+m+1); int cur=1; for(int i=1;i<=n;++i){ tmp[i]=((dis[i]-dis[0]+mod)*num[i])%mod; s[i]=(s[i-1]+tmp[i])%mod; while(q[cur].x==1&&q[cur].r==i){ ans[q[cur].id]=(s[i]-s[q[cur].l-1]+mod)%mod; cur++; } } bt(1,1,n); for(int i=2;i<=n;++i){ update(1,1,n,1,i-1,(dis[i]-dis[i-1]+mod)%mod); update(1,1,n,i,n,(dis[i-1]-dis[i]+mod)%mod); while(q[cur].x==i){ ans[q[cur].id]=query(1,1,n,q[cur].l,q[cur].r); cur++; } } for(int i=1;i<=m;++i) printf("%lld\n",ans[i]); }
以上是关于洛谷P3932浮游大陆的68号岛的主要内容,如果未能解决你的问题,请参考以下文章