2024.12.28模拟赛
耳机没电了
14:46 耳机彻底没电了,可是我明明记得早上充了电的
这应该是今年最后一次模拟赛了
打了T1正解、T2 25分暴力与T4 10分暴力,实际T2挂了15分,总分115,排名第六
现在也不知道暴力是怎么WA掉的
T1【签到题】
题目大意:
给出一个长度为 \(n\) 的序列 \(a_{i}\) ,要求输出 \(a\) 的每个前缀的优美度。
我们定义优美度为在一个序列中取出若干元素、使得这若干个元素两两的差都不为 \(k\) 的最大数目。\((1\leqslant n\leqslant 5\times 10^5,1\leqslant k,a_{i}\leqslant 10^9)\)
解题思路:
其实看完题目就想出怎么做了,但是想起来就像是一团浆糊,所以弄了很久。
离散化然后并查集直接做做完了
点击查看代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
int n,k;
struct node { int x,id; }a0[N];
int a[N];
int fa[N*3],sum[N*3];
map <int,int> mp;
int ans[N];
bool cmp1(node x,node y) { return x.x<y.x; }
bool cmp2(node x,node y) { return x.id<y.id; }
void init()//离散化
{
sort(a0+1,a0+1+n,cmp1);
for (int i=1;i<=n;i++)
{
sum[i]=1;
a[a0[i].id]=i;
mp[a0[i].x]=i;
}
sort(a0+1,a0+1+n,cmp2);
for (int i=1;i<=n*3;i++) fa[i]=i;
}
int find_fa(int x)
{
if (fa[x]==x) return x;
return fa[x]=find_fa(fa[x]);
}
void _merge(int x,int y)
{
int fa1=find_fa(x),fa2=find_fa(y);
if (fa1==fa2) return ;
fa[fa1]=fa2;
sum[fa2]+=sum[fa1];//集合中的有效贡献
sum[fa1]=0;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>k;
for (int i=1;i<=n;i++)
{
cin>>a0[i].x;
a0[i].id=i;
}
init();
for (int i=1;i<=n;i++)
{
int x=a0[i].x;
int fa1=find_fa(a[i]+n),fa2=-1,fa3=-1,fa4=find_fa(a[i]+(n<<1));
if (mp.find(x-k)!=mp.end()) fa2=find_fa(mp[x-k]);
if (mp.find(x+k)!=mp.end()) fa3=find_fa(mp[x+k]);
if (fa1==fa2) ans[i]-=(sum[fa1]+1)/2;
if (fa3==fa4) ans[i]-=(sum[fa4]+1)/2;
_merge(a[i],fa1);
_merge(a[i],fa4);
ans[i]+=ans[i-1]+(sum[find_fa(a[i])]+1)/2;
if (mp.find(x-k)!=mp.end()) _merge(a[i],mp[x-k]+(n<<1));
if (mp.find(x+k)!=mp.end()) _merge(a[i],mp[x+k]+n);
}
for (int i=1;i<=n;i++) cout<<ans[i]<<" ";
return 0;
}
T2【模板题】
题目大意:
有一个长度为 \(n\) 、初始值都为 \(1\) 、都为开状态的序列 \(a_{i}\) ,要求一下操作:
- \(1,l,p\) 将 \(a_{p}\) 切换开关状态
- \(2,l,r,x\) 将处于开状态的 \(a_{l}\sim a_{r}\) 的值乘上 \(x\)
- \(3,l,r,x\) 询问 \(a_{l}\sim a_{r}\) 是否都是 \(x\) 的倍数,若不是输出"\(NO\)",若是输出 "\(YES\)" 并将所有处于开状态的 \(a_{l}\sim a_{r}\) 的值除以 \(x\)
\((1\leqslant n\leqslant 10^5,1\leqslant x\leqslant 30)\)
解题思路:
首先,线段树
然后,发现 \(x\) 的范围30内有10个质因数,所以开10棵线段树分别记录每个区间内该质因子的数量(显然取最小值)
接着,开关状态说明有些时候存的值不可改,以后还可能再切回来继续用,所以可以设个替身代替闭状态的修改、等下次操作1时再把替身换掉即可。
查询时查的是原本的值。怎么办呢,那就让替身的值为正无穷,查询时取原值和替身的较小值就行了。30的修改不会让替身比原值还小的
点击查看代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f3f3f3f3f;
int n,m;
int pr[]={0,2,3,5,7,11,13,17,19,23,29};
struct node
{
int l,r;
int s1,s2;
int tag;
}tr[N<<2][15];
void pushup(int id,int p)
{
tr[id][p].s1=min(tr[id<<1][p].s1,tr[(id<<1)|1][p].s1);
tr[id][p].s2=min(tr[id<<1][p].s2,tr[(id<<1)|1][p].s2);
}
void push_down(int id,int p)
{
if (tr[id][p].tag)
{
int tg=tr[id][p].tag;
tr[id<<1][p].s1+=tg,tr[id<<1][p].tag+=tg;
tr[(id<<1)|1][p].s1+=tg,tr[(id<<1)|1][p].tag+=tg;
tr[id][p].tag=0;
}
}
int work(int p,int x)
{
int res=0;
while (x%p==0) x/=p,res++;
return res;
}
void build(int id,int l,int r,int p)
{
tr[id][p].l=l,tr[id][p].r=r;
if (l==r) { tr[id][p].s2=inf; return ; }
int mid=l+r>>1;
build(id<<1,l,mid,p);
build((id<<1)|1,mid+1,r,p);
pushup(id,p);
}
void update1(int id,int x,int p)
{
if (tr[id][p].l==tr[id][p].r&&tr[id][p].l==x) { swap(tr[id][p].s1,tr[id][p].s2); return ; }
push_down(id,p);
int mid=tr[id][p].l+tr[id][p].r>>1;
if (mid>=x) update1(id<<1,x,p);
else update1((id<<1)|1,x,p);
pushup(id,p);
}
void update2(int id,int l,int r,int x,int p)
{
if (tr[id][p].l>=l&&tr[id][p].r<=r)
{
tr[id][p].tag+=x;
tr[id][p].s1+=x;
return ;
}
push_down(id,p);
int mid=tr[id][p].l+tr[id][p].r>>1;
if (l<=mid) update2(id<<1,l,r,x,p);
if (mid+1<=r) update2((id<<1)|1,l,r,x,p);
pushup(id,p);
}
int query(int id,int l,int r,int p)
{
if (tr[id][p].l>=l&&tr[id][p].r<=r) return min(tr[id][p].s1,tr[id][p].s2);
push_down(id,p);
int mid=tr[id][p].l+tr[id][p].r>>1,res=inf;
if (l<=mid) res=min(res,query(id<<1,l,r,p));
if (mid+1<=r) res=min(res,query((id<<1)|1,l,r,p));
return res;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for (int i=1;i<=10;i++) build(1,1,n,i);
while (m--)
{
int op,l,r,x;
cin>>op;
if (op==1)
{
cin>>x;
for (int i=1;i<=10;i++) update1(1,x,i);
}
else if (op==2)
{
cin>>l>>r>>x;
for (int i=1;i<=10;i++) if (x%pr[i]==0) update2(1,l,r,work(pr[i],x),i);
}
else
{
cin>>l>>r>>x;
bool flag=true;
for (int i=1;i<=10;i++)
{
if (x%pr[i]==0&&query(1,l,r,i)<work(pr[i],x)) { flag=false; break; }
}
if (flag)
{
cout<<"YES\n";
for (int i=1;i<=10;i++) if (x%pr[i]==0) update2(1,l,r,-work(pr[i],x),i);
}
else cout<<"NO\n";
}
}
return 0;
}