[THUPC2022决赛] rsraogps

52 篇文章 0 订阅

洛谷P8421 [THUPC2022 决赛] rsraogps

题目大意

给定三个序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an b 1 , ⋯   , b n b_1,\cdots,b_n b1,,bn c 1 , ⋯   , c n c_1,\cdots,c_n c1,,cn

定义区间 [ l , r ] [l,r] [l,r]的价值为 a l , … , a r a_l,\dots,a_r al,,ar按位与, b l , ⋯   , b r b_l,\cdots,b_r bl,,br按位或, c l , ⋯   , c r c_l,\cdots,c_r cl,,cr的最大公约数,这三者的乘积。

m m m次查询,每次查询给出区间 [ l , r ] [l,r] [l,r],查询满足 l ≤ l ′ ≤ r ′ ≤ r l\leq l'\leq r'\leq r llrr [ l ′ , r ′ ] [l',r'] [l,r]的价值之和。

输出答案模 2 32 2^{32} 232后的值。

1 ≤ n ≤ 1 0 6 , 1 ≤ m ≤ 5 × 1 0 6 , 1 ≤ a i , b i , c i ≤ n , 1 ≤ l ≤ r ≤ n 1\leq n\leq 10^6,1\leq m\leq 5\times 10^6,1\leq a_i,b_i,c_i\leq n,1\leq l\leq r\leq n 1n106,1m5×106,1ai,bi,cin,1lrn


题解

我们先把询问离线下来,做扫描线,扫描 r r r

A r , i = a i & a i + 1 & ⋯ & a r A_{r,i}=a_i\& a_{i+1}\&\cdots\&a_r Ar,i=ai&ai+1&&ar B r , i = b i ∣ b i + 1 ∣ ⋯ ∣ b r B_{r,i}=b_i|b_{i+1}|\cdots|b_r Br,i=bibi+1br C r , i = gcd ⁡ ( c i , c i + 1 , ⋯   , c r ) C_{r,i}=\gcd(c_i,c_{i+1},\cdots,c_r) Cr,i=gcd(ci,ci+1,,cr)

在扫描 r r r的时候,对于每个 i i i维护 s r , i = s r − 1 , i + ∑ j = 1 i A r , j × B r , j × C r , j s_{r,i}=s_{r-1,i}+\sum\limits_{j=1}^iA_{r,j}\times B_{r,j}\times C_{r,j} sr,i=sr1,i+j=1iAr,j×Br,j×Cr,j,那么答案为 s r , r − s r , l − 1 s_{r,r}-s_{r,l-1} sr,rsr,l1

然而,我们发现,如果存在一个位置 j j j,满足 A r , j = = A r − 1 , j A_{r,j}==A_{r-1,j} Ar,j==Ar1,j,则 ∀ k ≤ j \forall k\leq j kj,都满足 A r , k = = A r − 1 , k A_{r,k}==A_{r-1,k} Ar,k==Ar1,k。也就是说,当 r r r右移一位时,有一部分 A A A不受影响, B B B C C C同理, A , B , C A,B,C A,B,C都不变的这部分对 s r , i s_{r,i} sr,i的增量是不变的。

我们可以从 i i i往前一个一个找,直到找到第一个满足 A r , j = = A r − 1 , j A_{r,j}==A_{r-1,j} Ar,j==Ar1,j B B B C C C同样满足的位置 j j j。这样做一次看似是 O ( n ) O(n) O(n)的,但是 A r , i , B r , i , C r , i A_{r,i},B_{r,i},C_{r,i} Ar,i,Br,i,Cr,i在随着 i i i减小时,最多只会改变 O ( log ⁡ n ) O(\log n) O(logn)次值,在最坏情况下,也只需要往前找 O ( log ⁡ n ) O(\log n) O(logn)次,时间复杂度是 O ( log ⁡ n ) O(\log n) O(logn)的。

a d i ad_i adi表示前 i i i个值在 r r r右移一位时对 s s s的增量(即 ∑ j = 1 i A r , j × B r , j × C r , j \sum\limits_{j=1}^iA_{r,j}\times B_{r,j}\times C_{r,j} j=1iAr,j×Br,j×Cr,j), l s t i lst_i lsti表示 A r , i , B r , i , C r , i A_{r,i},B_{r,i},C_{r,i} Ar,i,Br,i,Cr,i上次被修改的时间戳, v i v_i vi表示位置 i i i最后一次被修改前的贡献。对于当前的 r r r,找到满足上面条件的位置 j j j,并更新 j j j i i i之间的 v v v a d ad ad l s t lst lst

那么, s r , i = v i + ( r − l s t i ) × a d i s_{r,i}=v_i+(r-lst_i)\times ad_i sr,i=vi+(rlsti)×adi,对于询问 l , r l,r l,r,答案为 s r , r − s r , l − 1 s_{r,r}-s_{r,l-1} sr,rsr,l1

unsigned int \text{unsigned int} unsigned int即可解决模 2 32 2^{32} 232的问题。

可以参考代码,方便理解。

时间复杂度为 O ( n log ⁡ n + m ) O(n\log n+m) O(nlogn+m)

code

#include<bits/stdc++.h>
using namespace std;
const int N=1000000,M=5000000;
int n,m,now,lst[N+5];
unsigned int a[N+5],b[N+5],c[N+5],v[N+5],ad[N+5],ans[M+5];
struct node{
	int l,id;
};
vector<node>w[N+5];
unsigned int gcd(int i,int j){
	while(j){
		i%=j;swap(i,j);
	}
	return i;
}
unsigned int gt(int i){
	return v[i]+ad[i]*(now-lst[i]);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%u",&a[i]);
	for(int i=1;i<=n;i++) scanf("%u",&b[i]);
	for(int i=1;i<=n;i++) scanf("%u",&c[i]);
	for(int i=1,l,r;i<=m;i++){
		scanf("%d%d",&l,&r);
		w[r].push_back((node){l,i});
	}
	for(int i=1;i<=n;i++){
		int j=i-1;
		while(j){
			int v1,v2,v3;
			v1=a[j]&a[j+1];
			v2=b[j]|b[j+1];
			v3=gcd(c[j],c[j+1]);
			if(v1==a[j]&&v2==b[j]&&v3==c[j]) break;
			a[j]=v1;b[j]=v2;c[j]=v3;
			--j;
		}
		v[i]=gt(i-1);
		for(int k=j+1;k<=i;k++){
			v[k]=gt(k);
			ad[k]=ad[k-1]+a[k]*b[k]*c[k];
			lst[k]=now;
		}
		++now;
		for(int k=0;k<w[i].size();k++){
			ans[w[i][k].id]=gt(i)-gt(w[i][k].l-1);
		}
	}
	for(int i=1;i<=m;i++){
		printf("%u\n",ans[i]);
	}
	return 0;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值