时间限制: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