Codeforces 1058 Div 2 (A-F)

在 Print 之前

突然发现已经很久没写过博客了,前一晚才搭好这个博客样式,正好晚上熬夜打一下 Div 2。

赛时3941分,排在471位,T5双指针写挂了,调了一个小时没调出来

A - MEX Partition

水题一道

不难发现,答案就是 \(MEX(A)\)

Code

#include <bits/stdc++.h>
#define pll pair<ll,ll>
#define pld pair<ld,ld>
typedef long long ll;
typedef long double ld;
typedef int praise_long_long;
namespace io {
	using namespace std;
	inline ll read() {
		char x=getchar();
		ll ans=0,f=1;
		while(x<'0'||x>'9') {
			if(x=='-') {
				f*=(-1);
			}
			x=getchar();
		}
		while(x>='0'&&x<='9') {
			ans*=10;
			ans+=(x-'0');
			x=getchar();
		}
		return ans*f;
	}
	inline void print(ll x) {
		if(x<0) {
			putchar('-');
			x=-x;
		}
		if(x>=10) {
			print(x/10);
			putchar(x%10+'0');
		}
		else {
			putchar(x+'0');
		}
	}
}
using namespace io;
const ll N=2e5+5,mod=1e9+7,inf=2e18;
const ld eps=1e-6;
ll n,a[N]; 
inline void solve() {
	n=read();
	ll cnt=0;
	for(ll i=1;i<=n;i++) {
		a[i]=read();
	}
	sort(a+1,a+1+n);
	for(ll i=1;i<=n;i++) {
		if(a[i]!=cnt) {
			break;
		}
		else {
			while(a[i]==a[i+1]) {
				i++;
			}
			cnt++;
		}
	}
	print(cnt);
	puts("");
}
praise_long_long main() {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ll T=1;
	T=read();
	while(T--) {
		solve();
	}
	return 0;
}
/**/

B - Distinct Elements

其实不难发现,当 \(a_i\) 在之前没有出现过时,则有 \(b_i-b_{i-1}=i\),这样我们就可以给 \(a_i\) 安一个新的数。

反之若 \(b_i-b_{i-1} \not = i\),则 \(a_i\) 必定与 \(a_{i-(b_i-b_{i-1})}\) 相同。

Code

#include <bits/stdc++.h>
#define pll pair<ll,ll>
#define pld pair<ld,ld>
typedef long long ll;
typedef long double ld;
typedef int praise_long_long;
namespace io {
	using namespace std;
	inline ll read() {
		char x=getchar();
		ll ans=0,f=1;
		while(x<'0'||x>'9') {
			if(x=='-') {
				f*=(-1);
			}
			x=getchar();
		}
		while(x>='0'&&x<='9') {
			ans*=10;
			ans+=(x-'0');
			x=getchar();
		}
		return ans*f;
	}
	inline void print(ll x) {
		if(x<0) {
			putchar('-');
			x=-x;
		}
		if(x>=10) {
			print(x/10);
			putchar(x%10+'0');
		}
		else {
			putchar(x+'0');
		}
	}
}
using namespace io;
const ll N=2e5+5,mod=1e9+7,inf=2e18;
const ld eps=1e-6;
ll n,a[N],b[N];
set<ll> st;
inline void solve() {
	n=read();
	st.clear();
	for(ll i=1;i<=n;i++) {
		b[i]=read();
		st.insert(i);
	}
	for(ll i=1;i<=n;i++) {
		if(b[i]==b[i-1]) {
			a[i]=a[i-1];
		}
		else {
			a[i]=b[i]-b[i-1];
		}
		ll lt=i-a[i];
		if(!lt) {
			a[i]=(*st.begin());
			st.erase(st.begin());
		}
		else {
			a[i]=a[lt];
		}
	}
	for(ll i=1;i<=n;i++) {
		cout<<a[i]<<' ';
	}
	puts("");
}
praise_long_long main() {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ll T=1;
	T=read();
	while(T--) {
		solve();
	}
	return 0;
}
/**/

C - Reverse XOR

\(6\) 举例子,它的二进制是 \(110_2\),我们发现只需在开头加上一个 \(0\) 或在结尾减去一个 \(0\) 即可。

所以可以删去末尾的 \(0\) 来完成或者在开头添加 \(0\) 即可。

注意奇数的回文串中间一位应为 \(0\)

Code

#include <bits/stdc++.h>
#define pll pair<ll,ll>
#define pld pair<ld,ld>
typedef long long ll;
typedef long double ld;
typedef int praise_long_long;
namespace io {
	using namespace std;
	inline ll read() {
		char x=getchar();
		ll ans=0,f=1;
		while(x<'0'||x>'9') {
			if(x=='-') {
				f*=(-1);
			}
			x=getchar();
		}
		while(x>='0'&&x<='9') {
			ans*=10;
			ans+=(x-'0');
			x=getchar();
		}
		return ans*f;
	}
	inline void print(ll x) {
		if(x<0) {
			putchar('-');
			x=-x;
		}
		if(x>=10) {
			print(x/10);
			putchar(x%10+'0');
		}
		else {
			putchar(x+'0');
		}
	}
}
using namespace io;
const ll N=2e5+5,mod=1e9+7,inf=2e18;
const ld eps=1e-6;
ll n,cnt;
string num,sum;
inline void solve() {
	n=read();
	cnt=0;
	sum="";
	num="";
	while(n) {
		num+=(char)(n%2+'0');
		n/=2;
		cnt++;
	}
	reverse(num.begin(),num.end());
	for(ll i=cnt;i<=cnt*2;i++) {
		string t=sum+num;
		string kl=t;
		reverse(kl.begin(),kl.end());
		if(t==kl) {
			if(i&1) {
				if(t[i/2]=='0') {
					puts("YES");
					return ;
				}
			}
			else {
				puts("YES");
				return ;
			}
		}
		sum+='0';
	}
	puts("NO");
}
praise_long_long main() {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ll T=1;
	T=read();
	while(T--) {
		solve();
	}
	return 0;
}
/**/

D - MAD Interactive Problem

我们可以发现当我们查询第 \(i\) 位之前的查询为 \(0\),但第 \(i\) 位查询时不为 \(0\),那么第 \(i\) 位肯定是查询所得的数。

同理,当我们确定了一个 \(n\) 的排列后可以用同样的方法求出 \(i\) 号元素第一次出现的位置。

\(2*n\) 次访问出第二个 \(i\) 的位置,然后再用 \(n\) 次查询来锁定第一个位置,总查询次数是 \(3*n\)

Code

#include <bits/stdc++.h>
#define pll pair<ll,ll>
#define pld pair<ld,ld>
typedef long long ll;
typedef long double ld;
typedef int praise_long_long;
namespace io {
	using namespace std;
	inline ll read() {
		char x=getchar();
		ll ans=0,f=1;
		while(x<'0'||x>'9') {
			if(x=='-') {
				f*=(-1);
			}
			x=getchar();
		}
		while(x>='0'&&x<='9') {
			ans*=10;
			ans+=(x-'0');
			x=getchar();
		}
		return ans*f;
	}
	inline void print(ll x) {
		if(x<0) {
			putchar('-');
			x=-x;
		}
		if(x>=10) {
			print(x/10);
			putchar(x%10+'0');
		}
		else {
			putchar(x+'0');
		}
	}
}
using namespace io;
const ll N=6e2+5,mod=1e9+7,inf=2e18;
const ld eps=1e-6;
ll n,a[N],num[N],cnt,vis[N];
inline void input() {
	cout<<"? "<<cnt;
	cout.flush();
	for(ll i=1;i<=cnt;i++) {
		cout<<' '<<num[i];
		cout.flush();
	}
	puts("");
	cout.flush();
}
inline void input1() {
	for(ll i=1;i<=cnt;i++) {
		num[i]=vis[i];
	}
	input();
}
inline void solve() {
	n=read();
	cnt=0;
	num[++cnt]=1;
	a[1]=0;
	for(ll i=2;i<=2*n;i++) {
		a[i]=0;
		num[++cnt]=i;
		input();
		ll sum=read();
		if(sum) {
			a[i]=sum;
			vis[sum]=i;
			cnt--;
		}
	}
	cnt=n;
	for(ll i=1;i<=2*n;i++) {
		if(a[i]) {
			continue;
		}
		vis[++cnt]=i;
		input1();
		ll sum=read();
		a[i]=sum;
		cnt--;
	}
	cout<<'!';
	cout.flush();
	for(ll i=1;i<=2*n;i++) {
		cout<<' '<<a[i];
		cout.flush();
	}
	puts("");
	cout.flush();
}
praise_long_long main() {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ll T=1;
	T=read();
	while(T--) {
		solve();
	}
	return 0;
}
/**/

E - Rectangles

事实上 \(O(n^2 m^2)\) 的复杂度还是挺好想的,只需确定矩形的上下界,然后找到这区间内的所有可以对应的点,更新它们两两之间的点的最小值。

但如何把复杂度压下来呢?

不难发现,最费事情的就是更新最小值,那有没有办法降低这个复杂度呢?

事实上,我们可以用一个十分经典的 \(min\) 前缀和来实现。

因为我们是从上往下来搜索的,所以上面的部分是不会被更新的。

而下面部分,如果说这一列的后面的值比当前位置的小,又因为当前位置到矩形的上方是可以被后面包含的,那么就把这一位更新为后一位。

这样的复杂度为 \(O(n^2 m)\)

但当 \(n\) 很大时复杂度爆表,但反向枚举 \(m\) 却更优,所以当 \(n>m\) 时就枚举 \(m\) 即可,思路与上方一致。

最终复杂度:\(O(min(n,m)nm)\)

Code

#include <bits/stdc++.h>
#define pll pair<ll,ll>
#define pld pair<ld,ld>
typedef long long ll;
typedef long double ld;
typedef int praise_long_long;
namespace io {
	using namespace std;
	inline ll read() {
		char x=getchar();
		ll ans=0,f=1;
		while(x<'0'||x>'9') {
			if(x=='-') {
				f*=(-1);
			}
			x=getchar();
		}
		while(x>='0'&&x<='9') {
			ans*=10;
			ans+=(x-'0');
			x=getchar();
		}
		return ans*f;
	}
	inline void print(ll x) {
		if(x<0) {
			putchar('-');
			x=-x;
		}
		if(x>=10) {
			print(x/10);
			putchar(x%10+'0');
		}
		else {
			putchar(x+'0');
		}
	}
}
using namespace io;
const ll N=2.5e5+5,mod=1e9+7,inf=2e18;
const ld eps=1e-6;
ll n,m;
vector<ll> num;
inline void solve() {
	n=read(),m=read();
	vector<ll> v[min(n,m)+5];
	ll ans[n+5][m+5];
	for(ll i=1;i<=min(n,m);i++) {
		v[i].clear();
	}
	for(ll i=1;i<=n;i++) {
		for(ll j=1;j<=m;j++) {
			ans[i][j]=inf;
		}
	}
	for(ll i=1;i<=n;i++) {
		for(ll j=1;j<=m;j++) {
			char c;
			cin>>c;
			if(c=='1') {
				if(n<=m) {
					v[i].push_back(j);
				}
				else {
					v[j].push_back(i);
				}
			}
		}
	}
	if(n<=m) {
		for(ll u=1;u<=n;u++) {
			if(v[u].size()<2) {
				continue;
			}
			for(ll d=u+1;d<=n;d++) {
				if(v[d].size()<2) {
					continue;
				}
				vector<ll> al=v[u],bl=v[d];
				ll l=0,r=0;
				num.clear();
				while(l<al.size()&&r<bl.size()) {
					if(al[l]==bl[r]) {
						num.push_back(bl[r]);
						l++;
						r++;
					}
					else if(al[l]<bl[r]) {
						l++;
					}
					else {
						r++;
					}
				}
//				cout<<u<<' '<<d<<endl;
//				for(auto it : num) {
//					cout<<it<<' ';
//				}
//				puts("");
				if(num.size()<2) {
					continue;
				}
				for(ll i=1;i<num.size();i++) {
					for(ll j=num[i-1];j<=num[i];j++) {
						ans[d][j]=min(ans[d][j],(d-u+1)*(num[i]-num[i-1]+1));
					}
				}
			}
			for(ll i=n-1;i>=u;i--) {
				for(ll j=1;j<=m;j++) {
					ans[i][j]=min(ans[i][j],ans[i+1][j]);
				}
			}
		}
	}
	else {
		for(ll u=1;u<=m;u++) {
			if(v[u].size()<2) {
				continue;
			}
			for(ll d=u+1;d<=m;d++) {
				if(v[d].size()<2) {
					continue;
				}
				vector<ll> al=v[u],bl=v[d],cl;
				ll l=0,r=0;
				num.clear();
				while(l<al.size()&&r<bl.size()) {
					if(al[l]==bl[r]) {
						num.push_back(bl[r]);
						l++;
						r++;
					}
					else if(al[l]<bl[r]) {
						l++;
					}
					else {
						r++;
					}
				}
				if(num.size()<2) {
					continue;
				}
				for(ll i=1;i<num.size();i++) {
					for(ll j=num[i-1];j<=num[i];j++) {
						ans[j][d]=min(ans[j][d],(d-u+1)*(num[i]-num[i-1]+1));
					}
				}
			}
			for(ll i=m-1;i>=u;i--) {
				for(ll j=1;j<=n;j++) {
					ans[j][i]=min(ans[j][i],ans[j][i+1]);
				}
			}
		}
	}
	for(ll i=1;i<=n;i++) {
		for(ll j=1;j<=m;j++) {
			if(ans[i][j]==inf) {
				ans[i][j]=0;
			}
			print(ans[i][j]);
			putchar(' ');
		}
		puts("");
	}
}
praise_long_long main() {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ll T=1;
	T=read();
	while(T--) {
		solve();
	}
	return 0;
}

F - Twin Polynomials

这题说实话只要想明白了就很简单,但想歪了……

我们发现,如果 \(a_i\) 有值但 \(a_{a_i}\) 没值时,\(a_{a_i}\) 必定等于 \(i\)

如果 \(a_i\) 有值 \(a_{a_i}\) 也有值时,若 \(a_{a_i} \not = i\) 时,则这个方案无效,否则继续。

但剩下的怎么办呢?

不难想到,想让 \(a_i\) 合法,他只有可能等于 \(0\)、等于 \(i\)、连向其他一个点这三种情况。

就这样我们不难想到这是个 \(dp\)

\(f_i\) 表示当有i个点剩余的合法方案数,等于 \(0\) 就是加上 \(f_{i-1}\),等于自己也是加上 \(f_{i-1}\),而选择另一个点就是加上 \((i-1)*f_{i-2}\)

所以状态转移就是:

\[f_i=2*f_{i-1}+(i-1)*f_{i-2} \]

注意 \(a_n\) 不能为 \(0\),所以如果最后 \(a_n=-1\) 答案需要减掉 \(f_{cnt-1}\),其中 \(cnt\) 为剩余的 \(a_i=-1\) 的个数。

Code

#include <bits/stdc++.h>
#define pll pair<ll,ll>
#define pld pair<ld,ld>
typedef long long ll;
typedef long double ld;
typedef int praise_long_long;
namespace io {
	using namespace std;
	inline ll read() {
		char x=getchar();
		ll ans=0,f=1;
		while(x<'0'||x>'9') {
			if(x=='-') {
				f*=(-1);
			}
			x=getchar();
		}
		while(x>='0'&&x<='9') {
			ans*=10;
			ans+=(x-'0');
			x=getchar();
		}
		return ans*f;
	}
	inline void print(ll x) {
		if(x<0) {
			putchar('-');
			x=-x;
		}
		if(x>=10) {
			print(x/10);
			putchar(x%10+'0');
		}
		else {
			putchar(x+'0');
		}
	}
}
using namespace io;
const ll N=4e5+5,mod=1e9+7,inf=2e18;
const ld eps=1e-6;
ll n,a[N],cnt,f[N];
inline void solve() {
	n=read();
	cnt=0;
	for(ll i=0;i<=n;i++) {
		a[i]=read();
	}
	bool fl=0;
	for(ll i=1;i<=n;i++) {
		if(a[i]==-1||a[i]==0) {
			continue;
		}
		if(a[i]>n||(i!=a[a[i]]&&a[a[i]]!=-1)) {
			fl=1;
			break;
		}
		if(a[a[i]]==-1) {
			a[a[i]]=i;
		}
	}
	if(fl) {
		puts("0");
		return ;
	}
	for(ll i=1;i<=n;i++) {
		if(a[i]==-1) {
			cnt++;
		}
	}
	f[0]=1,f[1]=2;
	for(ll i=2;i<=cnt;i++) {
		f[i]=f[i-1]*2+(i-1)*f[i-2];
		f[i]%=mod;
	}
	if(a[n]==-1) {
		f[cnt]-=f[cnt-1];
		f[cnt]+=mod;
		f[cnt]%=mod;
	}
	print(f[cnt]);
	puts("");
}
praise_long_long main() {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ll T=1;
	T=read();
	while(T--) {
		solve();
	}
	return 0;
}
/**/
posted @ 2025-10-13 15:00  Ptll  阅读(55)  评论(0)    收藏  举报