F.Enchanted

https://codeforces.com/gym/105139/problem/F24湖北省赛F

看了一下前面两种操作,做法不是很明显

后面两种操作,一看就是可持久化线段树,单点修改,版本复制

接下来解决前面的两种操作

第一个操作

两个相同的合成一个新的(3+3->4),感觉是二进制,

举个例子,[1,2,2,4]->[1,3,4]最大是4, 我们模拟二进制运算,我们维护(2^{a[i]]})就可以转化成二进制,(1021)->(1101),找最高位1的位置即可,__lg函数得到答案

第二个操作

沿着第一个操作思路以及例子,k=3,(1101)+(100)->(10001),发现高位的1,1都向前进了,比k低位的1不会有贡献,我们就可以模拟这个操作,计算贡献

#include<iostream>
#define INF (1ll<<61)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int mo=19260817;
const int N=1e6+9;
int a[N];
int n,m;
ll A;
int p,q;
//可持久化线段树
struct KCJSEG{
    struct node{
	    int l,r;
	    ll val;
	}seg[N<<5];
	#define tl(id) seg[id].l
	#define tr(id) seg[id].r
	#define pushup(id) seg[id].val=seg[tl(id)].val+seg[tr(id)].val
	int root[N],index,mx;
	int inrange(int L,int R,int l,int r){return L>=l && R<=r;}
	int outofrange(int L,int R,int l,int r){return L>r || l>R;}
	void build(int &id,int l,int r){
	    id=++index;
	    if(l==r){
	        seg[id].val=a[l];
	        return;
	    }
	    int mid=(l+r)>>1;
	    build(tl(id),l,mid);
	    build(tr(id),mid+1,r);
	    pushup(id);
	}
	void update(int post,int &curr,int l,int r,int pos,int v){
	    curr=++index;
	    seg[curr]=seg[post];
	    if(l==r){
	        seg[curr].val=v;
	        return;
	    }
	    int mid=(l+r)>>1;
	    if(mid>=pos){
	        update(tl(post),tl(curr),l,mid,pos,v);
	    }else{
	        update(tr(post),tr(curr),mid+1,r,pos,v);
	    }
	    pushup(curr);
	}
	ll query(int curr,int L,int R,int l,int r){
		if(inrange(L,R,l,r)){
			return seg[curr].val;
		}else if(!outofrange(L,R,l,r)){
			int mid=(L+R)>>1;
			return query(tl(curr),L,mid,l,r)+query(tr(curr),mid+1,R,l,r);
		}else{
			return 0;
		}
	}
}tr;
void rnd(){	
	A*=7;
	A+=13;
	A%=mo;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m>>A>>p>>q;
	for(int i=1;i<=n;i++){
		rnd();
		a[i]=(A%q)+1;
	}
	for(int i=1;i<=n;i++){
		a[i]=1ll<<a[i];
	}
	tr.build(tr.root[0],1,n);
	for(int i=1;i<=m;i++){
		tr.root[i]=tr.root[i-1];
		rnd();
		int opt=(A%p)+1;
		if(opt==1){
			rnd();
			int L=(A%n)+1;
			rnd();
			int R=(A%n)+1;
			int l=min(L,R);
			int r=max(L,R);
			ll ans=tr.query(tr.root[i],1,n,l,r);
			cout<<__lg(ans)<<'\n';//log2()
		}else if(opt==2){
			rnd();
			int L=(A%n)+1;
			rnd();
			int R=(A%n)+1;
			int l=min(L,R);
			int r=max(L,R);
			rnd();
			int k=(A%q)+1;
			ll res=tr.query(tr.root[i],1,n,l,r);
			ll ans=0;
			for(int j=0;res;j++){
				if(j>=k){
					if(res&1){
						ans+=(1ll<<(j+1))%mod;
						ans%=mod;
					}else{
						break;
					}
				}
				res>>=1;
			}
			cout<<(ans%mod+mod)%mod<<'\n';
		}else if(opt==3){
			rnd();
			int pos=(A%n)+1;
			rnd();
			ll k=(A%q)+1;
			k=(1ll<<k);
			tr.update(tr.root[i-1],tr.root[i],1,n,pos,k);
		}else{
			rnd();
			int t=A%i;
			tr.root[i]=tr.root[t];
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值