【题目】
题目描述:
在成都的一条街道上,一共有 户人家,每个家庭有 个人,他们和谐的生活在一起,作为全国和谐街道,他们经常会小范围组织活动,每次活动会选择一户作为聚点, 并要求某些家庭参加,为了方便通知,村长每次邀请位置连续的家庭。因为每户人数不同,每个家庭之间有一定距离,村长希望你计算出每次邀请的家庭的移动代价。第 个家庭移动到家庭 的代价是:
表示 到 的距离,村长一共安排了 次聚会,每次邀请 [ , ] 的家庭参加
输入格式:
第一行两个数表示 ,
第二行 个数,第 个数表示第 个家庭与第 个家庭的距离
第三行 个数,表示每个家庭的人数
之后 行每行三个数 ,表示查询要把区间 [ , ] 的家庭移动到 点的代价和
输出格式:
对于每个询问输出一个数表示答案,对 取模
样例数据:
输入
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% 的数据, , ≤ 1000
对于另外 20% 的数据,所有家庭间的距离都为 1
对于另外 20% 的数据,所有家庭人数都为 1
对于 100% 的数据 ,, ≤ 200000;, ≤
【分析】
我这道题爆精度了,本来 100 的现在只有 30 呜呜呜
若我们知道了区间 [ , ] 要移动到 ,分以下三种情况讨论:
(先解释一下变量, 是 号家庭的人数, 是从 到 的距离(就是前缀和,方便计算距离))
(1)若 > ,[ , ] 在 的右边, =
(2)若 < ,[ , ] 在 的左边, =
(3)若 ≤ ≤ ,即 在 [ , ] 的中间,拆成上述两个区间就可以了
由于没有修改操作,用前缀和就行了,不用写线段树(但我写的线段树),时间复杂度 O()
有一个要注意的地方,即若求 =( % % )% ,一定最后要写( + )% ,不然最后结果可能是负的
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define mod 19260817
using namespace std;
int d[N],x[N];
long long sum1[N],sum2[N],sum3[N];
long long calc(int s,int l,int r,bool limit)
{
if(l>r) return 0;
long long ans1=((sum3[r]-sum3[l-1])%mod+mod)%mod;
long long ans2=((sum2[r]-sum2[l-1])%mod+mod)%mod;
ans1=ans1*sum1[s]%mod;
if(!limit) swap(ans1,ans2);
return ((ans1-ans2)%mod+mod)%mod;
}
int main()
{
// freopen("party.in","r",stdin);
// freopen("party.out","w",stdout);
int n,m,i,s,l,r;
scanf("%d%d",&n,&m);
for(i=2;i<=n;++i)
{
scanf("%d",&d[i]);
sum1[i]=(sum1[i-1]+d[i])%mod;
}
for(i=1;i<=n;++i)
{
scanf("%d",&x[i]);
sum3[i]=(sum3[i-1]+x[i])%mod;
sum2[i]=(sum2[i-1]+sum1[i]*x[i])%mod;
}
for(i=1;i<=m;++i)
{
scanf("%d%d%d",&s,&l,&r);
long long ans1=calc(s,l,min(r,s-1),true);
long long ans2=calc(s,max(l,s+1),r,false);
printf("%lld\n",(ans1+ans2)%mod);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}