【题解】储物点的距离
储物点的距离
https://ac.nowcoder.com/acm/problem/14683
这是一个前缀和+分类讨论题,难点在前缀和应该要做成什么样子和算不同情况应该怎么计算。
前缀和有3个为:距离前缀和dis,数量前缀和num,1~i号仓库的物品都运送到1号点的前缀和sum。
然后分成3种情况讨论:
x在区间右边,x在区间左边,x在区间中间。
计算方法只有两种:把区间内的东西运送到左边和运送到右边。
对于第一种计算方法级记作calR:
先算出区间内的数量num[r]-num[l-1],然后我们知道前缀和sum是1~i号点都送到1号点的和,那么sum[r]-sum[l-1]就是这段区间送到1号点的和,然后减去1到x这段距离dis[x]就行了
即: (这里就不取模了)
对于第二种计算放假记作calL:
同时也先算出区间数量,然后我们把区间数量×dis[x],这样会多出sum[r]-sum[l-1]这段距离,减掉即可。
即:
然后对于三种情况:
第一种:直接calL(l,r,x)
第二种:直接calR(l,r,x)
第三种:calL(x,z,z)+calR(z,y,z)
代码:
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<vector> #include<cstring> #include<queue> #define fs first #define se second #define pb push_back #define cppio ios::sync_with_stdio(false);cin.tie(0) using namespace std; typedef long long ll; typedef pair<int,int> pii; typedef vector<int> VI; const int maxn=1e6+6; const ll inf=0x3f3f3f3f; const ll mod=1e9+7; int n,m; ll num[maxn]; ll dis[maxn]; ll sum[maxn]; ll calL(int l,int r,int x){ ll ans=0; ll tnum=(num[r]-num[l-1]+mod)%mod; ans=tnum*dis[x]%mod; ll tmp=(sum[r]-sum[l-1]+mod)%mod; ans=(ans+mod-tmp)%mod; return ans; } ll calR(int l,int r,int x){ ll ans=0; ll tnum=(num[r]-num[l-1]+mod)%mod; ans=(sum[r]+mod-sum[l-1])%mod; ans=(ans-tnum*dis[x]%mod+mod)%mod; return ans; } int main(){ scanf("%d%d",&n,&m); for(int i=2;i<=n;i++){ scanf("%lld",dis+i); dis[i]=(dis[i-1]+dis[i])%mod; } for(int i=1;i<=n;i++){ scanf("%lld",num+i); sum[i]=(sum[i-1]+num[i]*dis[i])%mod; num[i]=(num[i-1]+num[i])%mod; } for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&z,&x,&y); ll ans=0; if(z>=y){ ans=calL(x,y,z); } else if(z<=x){ ans=calR(x,y,z); } else{ ans=(calL(x,z,z)+calR(z,y,z))%mod; } printf("%lld\n",ans%mod); } return 0; }