【2018/10/02测试T1】【WOJ 4018】聚会

【题目】

题目描述:

在成都的一条街道上,一共有 n 户人家,每个家庭有 X_i 个人,他们和谐的生活在一起,作为全国和谐街道,他们经常会小范围组织活动,每次活动会选择一户作为聚点, 并要求某些家庭参加,为了方便通知,村长每次邀请位置连续的家庭。因为每户人数不同,每个家庭之间有一定距离,村长希望你计算出每次邀请的家庭的移动代价。第 i个家庭移动到家庭 j 的代价是:X_i\cdot dis(i,j)

dis(i,j) 表示 i 到 j 的距离,村长一共安排了 m 次聚会,每次邀请 [ L_iR_i ] 的家庭参加

输入格式:

第一行两个数表示 n , m

第二行 n-1 个数,第 i 个数表示第 i 个家庭与第 i+1 个家庭的距离 D_i

第三行 n 个数,表示每个家庭的人数 X_i

之后 m 行每行三个数 xlr,表示查询要把区间 [ l , r ] 的家庭移动到 x 点的代价和

输出格式:

对于每个询问输出一个数表示答案,对 19260817 取模

样例数据:

扫描二维码关注公众号,回复: 3441757 查看本文章

输入

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 ≤ 1000

对于另外 20% 的数据,所有家庭间的距离都为 1

对于另外 20% 的数据,所有家庭人数都为 1

对于 100% 的数据 ,nm ≤ 200000;X_iD_i ≤ 2\times 10^{9}

【分析】

我这道题爆精度了,本来 100 的现在只有 30 呜呜呜

若我们知道了区间 [ l , r ] 要移动到 s,分以下三种情况讨论:

(先解释一下变量,x_i 是 i 号家庭的人数,d_i 是从 1 到 i 的距离(就是前缀和,方便计算距离))

(1)若 l > s,[ l , r ] 在 s 的右边,ans=x_l(d_l-d_s)+x_{l+1}(d_{l+1}-d_s)+...+x_r(d_r-d_s) = \sum x_id_i- d_s\sum x_i

(2)若 r < s,[ l , r ] 在 s 的左边,ans=x_l(d_s-d_l)+x_{l+1}(d_s-d_{l+1})+...+x_r(d_s-d_r) = d_s\sum x_i-\sum x_id_i

(3)若 l ≤ s ≤ r,即 s 在 [ l , r ] 的中间,拆成上述两个区间就可以了

由于没有修改操作,用前缀和就行了,不用写线段树(但我写的线段树),时间复杂度 O(n

有一个要注意的地方,即若求 ans =(a % p-b % p)% p,一定最后要写(ans + p)% p,不然最后结果可能是负的

【代码】

#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;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/82926402
今日推荐