HS的新题

时间限制:3 s 内存限制:256 MB

【题目背景】

HS很想出题,今天在颓废的时候忽然脑子一抽,决定出道垃圾的原创题(也许吧!),也许是HS不想那么毒瘤 ,所以数据全为随机数据,望大家水之!!!

在这里插入图片描述

【题目描述】

有一个长度为n的数列,有m个操作,操作有8种!

1 l r x:将[l,r]上所有数变为x;

2 l r:对于[l,r]上每一个数ai变为1/ai;

3 l r x:将[l,r]上所有数乘以x;

4 l r x y:查询[l,r]上在[x,y]这一值域范围内数的个数;

5 l r:将[l,r]上所有数变为在[l,r]上所有数的平均数;

6 l r:查询[l,r]上所有数的众数,若有相同输出最小的那个;

7 l r:查询[l,r]上不同数的个数;

8 l r:在[l,r]选出一些数,查询这些数异或的最大值;

所有操作在 mod 998244353 下进行!

【输入格式】

第一行3个数n,m,

接下来一行n个数,表示初始数列,

接下来m行表示m个操作。

【输出格式】

对每一个查询操作输出答案

【样例输入】

10 10
9 1 9 1 8 1 3 5 5 1
7 5 6
7 9 5
5 7 10
3 1 7 1
1 1 1 7
1 1 9 7
7 5 6
1 1 9 1
7 3 1
5 1 1
【样例输出】
2
4
1
1

【提示】

30%数据 1<=n,m<=300;

100%数据 1<=n,m<=100000 1<=ai,x,y<=1e8;

注意不保证l<=r

题解

30分做法:
暴力处理每个操作,
对于操作1,3,4,5都是按照题目要求操作即可,单次O(n)的,对于其他操作单次O(nlogn)
对于操作2对每一个数取逆元即可
对于操作6,7,可以先把这些数记录下来排序,然后扫一遍即可得到众数和不同数个数,
对于操作8,线性基模版(不会?点这)打上即可。

#include<bits/stdc++.h>
#define maxn 100010
#define ll long long
#define IT set<node>::iterator
#define it vector<pair<ll,int> >::iterator
using namespace std;
int n,m;
ll a[maxn];
int read(){
	int x=0,ju=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')ju=-ju;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x;
}
const ll mod=(ll)998244353;
ll ksm(ll a,ll k){
    ll ans=(ll)1;
    while(k){
        if(k&1)ans=(ans*a)%mod;
        a=(a*a)%mod;k>>=1;
    }
    return ans;
}
void change(int _l,int _r,ll v){
    for(int i=_l;i<=_r;i++)a[i]=v;
    return;
}
void qn(int _l,int _r){
    for(int i=_l;i<=_r;i++)a[i]=ksm(a[i],mod-(ll)2);
    return;
}
void cheng(int _l,int _r,ll x){
    for(int i=_l;i<=_r;i++)a[i]=(a[i]*x)%mod;
    return;
}
ll qab(int _l,int _r,ll a1,ll a2){
	int ans=0;
    for(int i=_l;i<=_r;i++)if(a1<=a[i]&&a[i]<=a2)ans++;
    return ans;
}
ll qjz(int _l,int _r){
	ll ans=0;
    for(int i=_l;i<=_r;i++)ans+=a[i],ans%=mod;
    return (ans*ksm((ll)(_r-_l+1),mod-(ll)2))%mod;
}
ll qzs(int _l,int _r){
    vector<pair<ll,int> >q;
    for(int i=_l;i<=_r;i++)q.push_back(make_pair(a[i],1));
    sort(q.begin(),q.end());
    ll ans=0,sum=0;
    for(it i=q.begin();i!=q.end();i++){
        if((i+1)!=q.end())if(i->first==(i+1)->first){
        	((i+1)->second)+=(i->second);
        	continue;
        }
        if((i->second)>sum)ans=(i->first),sum=(i->second);
	}
    return ans;
}
ll qgs(int _l,int _r){
    vector<pair<ll,int> >q;
    for(int i=_l;i<=_r;i++)q.push_back(make_pair(a[i],1));
    sort(q.begin(),q.end());
    ll ans=0;
    for(it i=q.begin();i!=q.end();i++){
        if((i+1)!=q.end())if(i->first==(i+1)->first)continue;
        ans++;
	}
    return ans;
}
ll qma(int _l,int _r){
    vector<pair<ll,int> >q;
	ll ans=0,f[33]={0};
    for(int i=_l;i<=_r;i++)q.push_back(make_pair(a[i],1));
    for(it i=q.begin();i!=q.end();i++){
        if((i+1)!=q.end())if(i->first==(i+1)->first)continue;
    	ll a1=(i->first);
    	for(int j=31;j>=0;j--){
			if(((a1>>j)&1)==0)continue;
			if(!f[j]){f[j]=a1;break;}
			a1^=f[j];    		
    	}
	}
	for(int i=31;i>=0;i--)ans=max(ans,ans^f[i]);
    return ans%mod;
}
int main(){
	//freopen("xfdxt.in","r",stdin);
	//freopen("xfdxt.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=(ll)read();
    for(int i=1;i<=m;i++){
        int op,l,r,x,y;
        op=read();l=read();r=read();
        if(l>r)swap(l,r);
		if(op==1)x=read(),change(l,r,max((ll)1,(ll)x));
		if(op==2)qn(l,r);
		if(op==3)x=read(),cheng(l,r,(ll)x);
		if(op==4)x=read(),y=read(),printf("%lld\n",qab(l,r,(ll)x,(ll)y));
		if(op==5)change(l,r,max((ll)1,qjz(l,r)));
		if(op==6)printf("%lld\n",qzs(l,r));
		if(op==7)printf("%lld\n",qgs(l,r));
		if(op==8)printf("%lld\n",qma(l,r));
    }
    return 0;
}

100分做法:
由于数据是随机的,可以认为所有操作个数几乎相同,有两个特殊的操作(操作1和操作5),这两个操作都是把一段变成一个数,由于 l,r 也是随机的,可以用数学方法证明出区间长度期望为 n/3 并且随着操作1和操作5次数的增加,这个序列中不同数的段数趋近于logn 个,用珂朵莉树(不会?点这)维护每个相同的段然后按30分做法暴力处理每个操作即可AC!(其实出题人已经够良心的了!)
时间复杂度?O(n(logn)^2)

#include<bits/stdc++.h>
#define maxn 100010
#define ll long long
#define IT set<node>::iterator
#define it vector<pair<ll,int> >::iterator
using namespace std;
int read(){
	int x=0,ju=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')ju=-ju;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x;
}
const ll mod=(ll)998244353;
ll ksm(ll a,ll k){
    ll ans=(ll)1;
    while(k){
        if(k&1)ans=(ans*a)%mod;
        a=(a*a)%mod;k>>=1;
    }
    return ans;
}
struct node
{
    int l,r;
    mutable ll v;
    node(int l,int r=-1,ll v=0):l(l),r(r),v(v){}
    bool operator<(const node &a1)const{return l<a1.l;}
};
set<node>s;
IT split(int k){
    IT i=s.lower_bound(node(k));
    if(i!=s.end()&&i->l==k)return i;
    --i;
	int l=i->l,r=i->r;ll v=i->v;
    s.erase(i);s.insert(node(l,k-1,v));
    return s.insert(node(k,r,v)).first;
}
void change(int _l,int _r,ll v){
    IT r=split(_r+1),l=split(_l);
    s.erase(l,r);s.insert(node(_l,_r,v));
    return;
}
void qn(int _l,int _r){
    IT r=split(_r+1),l=split(_l);
    vector<int>s1,s2;vector<ll>s3;
    for(;l!=r;l++){
	    int a1=l->l,a2=l->r;
		ll a3=ksm(l->v,mod-(ll)2);
        s1.push_back(a1);s2.push_back(a2);s3.push_back(a3);
	}
	for(int i=0;i<s1.size();i++){
		s.erase(s1[i]);
		s.insert(node(s1[i],s2[i],s3[i]));
	}
    return;
}
void cheng(int _l,int _r,ll x){
    IT r=split(_r+1),l=split(_l);
    for(;l!=r;l++)l->v=(l->v*x)%mod;
    return;
}
ll qab(int _l,int _r,ll a1,ll a2){
    IT r=split(_r+1),l=split(_l);
    vector<pair<ll,int> >q;
    for(;l!=r;l++)q.push_back(make_pair(l->v,(l->r)-(l->l)+1));
    sort(q.begin(),q.end());
    ll ans=0;
    for(it i=q.begin();i!=q.end();i++)
	    if(a1<=(i->first)&&(i->first)<=a2)
            ans+=(ll)(i->second);
    return ans;
}
ll qjz(int _l,int _r){
    IT r=split(_r+1),l=split(_l);
    ll ans=0;
    for(;l!=r;l++)ans+=(l->v)*(ll)((l->r)-(l->l)+1),ans%=mod;
    return (ans*ksm((ll)(_r-_l+1),mod-(ll)2))%mod;
}
ll qzs(int _l,int _r){
    IT r=split(_r+1),l=split(_l);
    vector<pair<ll,int> >q;
    for(;l!=r;l++)q.push_back(make_pair(l->v,(l->r)-(l->l)+1));
    sort(q.begin(),q.end());
    ll ans=0,sum=0;
    for(it i=q.begin();i!=q.end();i++){
        if((i+1)!=q.end())if(i->first==(i+1)->first){
        	((i+1)->second)+=(i->second);
        	continue;
        }
        if((i->second)>sum)ans=(i->first),sum=(i->second);
	}
    return ans;
}
ll qgs(int _l,int _r){
    IT r=split(_r+1),l=split(_l);
    vector<pair<ll,int> >q;
    for(;l!=r;l++)q.push_back(make_pair(l->v,(l->r)-(l->l)+1));
    sort(q.begin(),q.end());ll ans=0;
    for(it i=q.begin();i!=q.end();i++){
        if((i+1)!=q.end())if(i->first==(i+1)->first)continue;
        ans++;
	}
    return ans;
}
ll qma(int _l,int _r){
    IT r=split(_r+1),l=split(_l);
    vector<pair<ll,int> >q;
	ll ans=0,f[33]={0};
    for(;l!=r;l++)q.push_back(make_pair(l->v,(l->r)-(l->l)+1));
    for(it i=q.begin();i!=q.end();i++){
        if((i+1)!=q.end())if(i->first==(i+1)->first)continue;
    	ll a1=(i->first);
    	for(int j=31;j>=0;j--){
			if(((a1>>j)&1)==0)continue;
			if(!f[j]){f[j]=a1;break;}
			a1^=f[j];    		
    	}
	}
	for(int i=31;i>=0;i--)ans=max(ans,ans^f[i]);
    return ans%mod;
}
int n,m;ll a[maxn];
int main(){
	//freopen("xfdxt.in","r",stdin);
	//freopen("xfdxt.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=n;i++){
	    a[i]=(ll)read();
		s.insert(node(i,i,a[i]));
	}
    s.insert(node(n+1,n+1,0));
    for(int i=1;i<=m;i++){
        int op,l,r,x,y;
        op=read();l=read();r=read();
        if(l>r)swap(l,r);
		if(op==1)x=read(),change(l,r,max((ll)1,(ll)x));
		if(op==2)qn(l,r);
		if(op==3)x=read(),cheng(l,r,(ll)x);
		if(op==4)x=read(),y=read(),printf("%lld\n",qab(l,r,(ll)x,(ll)y));
		if(op==5)change(l,r,max((ll)1,qjz(l,r)));
		if(op==6)printf("%lld\n",qzs(l,r));
		if(op==7)printf("%lld\n",qgs(l,r));
		if(op==8)printf("%lld\n",qma(l,r));
    }
    return 0;
}

感谢
两位神仙的博客!
1,线性基学习笔记 https://blog.sengxian.com/algorithms/linear-basis
2,骗分导论–ODT珂朵莉树 https://blog.csdn.net/niiick/article/details/83062256
小学弟给我的灵感!

题目出自 COGS 3139

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值