AtCoder Beginner Contest 350 解题报告

AtCoder Beginner Contest 350

A - Past ABCs

当且仅当串为 \(\texttt{ABC000},\texttt{ABC316},\texttt{ABC350}\sim\texttt{ABC999}\) 时输出 \(\texttt{No}\)

(本人因 \(000\) 挂了一发。)

#include<bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(false),cin.tie(nullptr);
//	int _;cin>>_;while(_--)

	int x;
	scanf("ABC%d",&x);
	puts(x<=349&&x!=316&&x?"Yes":"No");

	return 0;
}

B - Dentist Aoki

模拟。

#include<bits/stdc++.h>
using namespace std;

int n,k,a[1005];

int main()
{
	ios::sync_with_stdio(false),cin.tie(nullptr);
//	int _;cin>>_;while(_--)

	cin>>n>>k;
	fill(a+1,a+n+1,1);
	while(k--)
	{
		int x;cin>>x;
		a[x]^=1;
	}
	cout<<accumulate(a+1,a+n+1,0);

	return 0;
}

C - Sort

对于每个 \(i=1,2,\ldots,n-1\),依次将 \(i\) 归位即可。\(\Theta(n)\)

#include<bits/stdc++.h>
using namespace std;

const int N=200005;
int n,a[N],p[N];
vector<PII>ans;

int main()
{
	ios::sync_with_stdio(false),cin.tie(nullptr);
//	int _;cin>>_;while(_--)

	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i],p[a[i]]=i;
	for(int i=1;i<n;i++)
		if(a[i]!=i)
		{
			ans.PB(i,p[i]);
			swap(a[i],a[p[i]]),swap(p[i],p[a[p[i]]]);
		}
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i.fi<<" "<<i.se<<endl;

	return 0;
}

D - New Friends

可以发现每个连通块最后会被连成完全图。并查集维护即可。\(\Theta(n\alpha(n))\)

#include<bits/stdc++.h>
using namespace std;

const int N=200005;
int n,m;
int fa[N],cnt[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}

int main()
{
	ios::sync_with_stdio(false),cin.tie(nullptr);
//	int _;cin>>_;while(_--)

	cin>>n>>m;
	iota(fa+1,fa+n+1,1);
	for(int i=1,x,y;i<=m;i++)
		cin>>x>>y,fa[find(x)]=find(y);
	for(int i=1;i<=n;i++)cnt[find(i)]++;
	ll ans=-m;
	for(int i=1;i<=n;i++)ans+=cnt[i]*(cnt[i]-1ll)/2;
	cout<<ans;

	return 0;
}

E - Toward 0

由于 \(\left\lfloor\dfrac{\lfloor\frac nx\rfloor}y\right\rfloor=\left\lfloor\dfrac{\lfloor\frac ny\rfloor}x\right\rfloor=\left\lfloor\dfrac n{xy}\right\rfloor\),而骰子只有 \(1,2,3,4,5,6\) 的点数,可以发现可能到达的值一定形如 \(\left\lfloor\dfrac n{2^i3^j5^k}\right\rfloor\),这样的值是 \(\Theta(\mathrm{polylog}(n))\) 的。

然后就可以 dp 了,注意掷到 \(1\) 的情况:

\[dp_i=\min\left\{x+dp_{\lfloor\frac na\rfloor},\frac65y+\frac15\sum_{i=2}^6dp_{\lfloor\frac ni\rfloor}\right\}. \]

时间:\(\Theta(\mathrm{polylog}(n))\)

#include<bits/stdc++.h>
using namespace std;

ll n;
int a,x,y;
map<ll,double>f;

int main()
{
	ios::sync_with_stdio(false),cin.tie(nullptr);
//	int _;cin>>_;while(_--)

	cin>>n>>a>>x>>y;
	f[0]=0;
	for(ll i=1;i<=n;i<<=1)
		for(ll j=1;i*j<=n;j*=3)
			for(ll k=1;i*j*k<=n;k*=5)
				f[n/(i*j*k)]=0;
	for(auto &i:f)
	{
		if(!i.fi)i.se=0;
		else
		{
			double s1=x+f[i.fi/a],s2=6.0*y;
			for(int j=2;j<=6;j++)
				s2+=f[i.fi/j];
			s2/=5;
			i.se=min(s1,s2);
		}
	}
	cout<<fixed<<setprecision(20)<<f[n];

	return 0;
}

F - Transpose

这能给 \(550\) 分?

先把与每个括号匹配的括号的位置求出来,然后类似括号树地递归就行了。遇到括号在内部倒着扫,大小写随便处理一下就行了。\(\Theta(|S|)\)

#include<bits/stdc++.h>
using namespace std;

string s;
int pr[500005];
void sol(int x,int y)
{
	dbg(x,y);
	if(x<=y)
	{
		for(int i=x;i<=y;i++)
		{
			if(s[i]=='('){if(pr[i]!=i+1)sol(pr[i]-1,i+1);i=pr[i];}
			else cout<<s[i];
		}
	}
	else
	{
		for(int i=x;i>=y;	i--)
		{
			if(s[i]==')'){if(pr[i]!=i-1)sol(pr[i]+1,i-1);i=pr[i];}
			else cout<<s[i];
		}
	}
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(nullptr);
//	int _;cin>>_;while(_--)

	cin>>s;
	VI stk;
	for(int i=0;i<s.size();i++)
		if(s[i]=='(')stk.PB(i);
		else if(s[i]==')')pr[stk.back()]=i,pr[i]=stk.back(),stk.PPB();
		else
		{
			if(stk.size()&1)
			{
				if(s[i]>='a')s[i]-=32;
				else s[i]+=32;
			}
		}
	sol(0,s.size()-1);

	return 0;
}

G - Mediator

Shaber 题。

一种 naive 的想法是,用 bitset 维护相邻点集,查询时直接与一下就行了。但是空间会爆炸。

考虑套一层根号分治,如果一个点的度数不超过 \(B\) 就暴力。

具体地,如果加边时发现一个点的度数超过了 \(B\),就新开一个 bitset 存下。

查询时,如果有一个点的度数不超过 \(B\),那么就枚举这个点的相邻点暴力判断;否则就把它们的相邻点集与一下再看是否有 set bit 即可。

\(B=\Theta(\sqrt n)\),时空复杂度 \(\Theta\left(n\sqrt n+\dfrac{n^2}w\right)\)。(假设 \(n,q\) 同阶)

另:这个做法似乎不需要保证图一直是森林。

另:STL bitset 似乎没有 clz/ctz 函数,需要手写 bitset不不不是有的,但是我不知道,cppref 上也没有写。

#include<bits/stdc++.h>
using namespace std;

const int N=100005,S=(N>>6)+2,B=320;
#define ull unsigned ll
struct Bs
{
	ull s[S];
	void set(int p)
	{
		s[(p-1)>>6]|=1ull<<((p-1)&63);
	}
};
int n,q;
Bs* b[N];
VI adj[N];
set<PII>es;

int main()
{
	ios::sync_with_stdio(false),cin.tie(nullptr);
//	int _;cin>>_;while(_--)

	cin>>n>>q;
	int lans=0;
	while(q--)
	{
		int op,x,y;
		cin>>op>>x>>y;
		op=1+((op*(lans+1ll)%998244353)&1);
		x=1+((x*(lans+1ll)%998244353)%n);
		y=1+((y*(lans+1ll)%998244353)%n);
		if(op==1)
		{
			es.emplace(x,y);
			if(adj[x].size()>=B)
			{
				if(adj[x].size()==B)
				{
					b[x]=new Bs();
					for(int i:adj[x])b[x]->set(i);
				}
				b[x]->set(y);
			}
			adj[x].PB(y);
			if(adj[y].size()>=B)
			{
				if(adj[y].size()==B)
				{
					b[y]=new Bs();
					for(int i:adj[y])b[y]->set(i);
				}
				b[y]->set(x);
			}
			adj[y].PB(x);
		}
		else
		{
			if(adj[y].size()<=B)swap(x,y);
			if(adj[x].size()<=B)
			{
				lans=0;
				for(int j:adj[x])
					if(es.count(minmax(j,y)))
					{
						lans=j;
						break;
					}
				cout<<lans<<endl;
			}
			else
			{
				lans=0;
				for(int i=0;i<S;i++)
				{
					ull t=b[x]->s[i]&b[y]->s[i];
					if(t)
					{
						lans=(i<<6)+__builtin_ctzll(t)+1;
						break;
					}
				}
				cout<<lans<<endl;
			}
		}
	}

	return 0;
}
posted @ 2024-04-20 21:50  No_Play_Yes_Splay  阅读(415)  评论(3编辑  收藏  举报