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;
}
posted @ 2024-12-28 15:25  还是沄沄沄  阅读(6)  评论(1编辑  收藏  举报