Codeforces Round #803 (Div. 2)

复健!!!

A&B

C

如果有仨正数或者仨负数都不行,然后根据 \(0\) 的数量判断一下边界情况即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
const int N=1e6+10;
int a[N];map<int,bool> vis;
void sol()
{
	vis.clear();int n=read(),c=0;
	for(int i=1;i<=n;i++)a[i]=read(),vis[a[i]]=1,c+=!a[i];
	if(n<=100)
	{
		bool ok=1;
		for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)for(int k=j+1;k<=n;k++)ok&=vis[a[i]+a[j]+a[k]];
		if(ok)puts("YES");
		else puts("NO");
	}
	else if(n-c>=6)puts("NO");
	else if(n-c==1)puts("YES");
	else if(n-c==2)
	{
		int x[2]={0,0},cnt=0;
		for(int i=1;i<=n;i++){
			if(a[i])x[cnt++]=a[i];
		}
		if(x[0]+x[1]==0)puts("YES");
		else puts("NO");
	}
	else if(n==c)puts("YES");
	else puts("NO");
}
signed main()
{
	int T=read();
	while(T--)sol();
	return 0;
}

D

假设我们问的区间是 \([l,r]\),那么不难发现如果给的数列有奇数个在 \([l,r]\) 中的那么所求的数一定在此区间,然后二分即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
void sol()
{
	int n=read();
	int L=1,R=n;
	int cnt=0;
	while(L<R)
	{
		int mid=(L+R)>>1;
		printf("? %d %d\n",L,mid),fflush(stdout);
		assert((++cnt)<=15);
		int cnt=0;
		for(int i=1;i<=mid-L+1;i++){int x=read();if(x>=L&&x<=mid)cnt++;}
		if(cnt&1)R=mid;
		else L=mid+1;
	}
	printf("! %d\n",L);
	fflush(stdout);
}
int main()
{
	int T=read();
	while(T--)sol();
	return 0; 
}

E

首先把两个数组都置换一下,\(a_i=pos_{i}\) 这样。

从前往后考虑每个 \(b_i\),此时第 \(i\) 个操作等价于在后 \(s\)\(a\) 中选择一个数定在 \(b_i\) 上,依次算一下每个数的方案然后乘起来即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
const int mod=998244353,N=2e5+10;
int a[N],p[N],b[N];
bool vis[N],vis1[N];
void sol()
{
	int n=read(),s=read();
	for(int i=1;i<=n;i++)a[i]=read(),p[a[i]]=i;
	for(int i=1;i<=n;i++)a[i]=p[i],p[i]=vis1[i]=0;
	for(int i=1;i<=n;i++)
	{
		b[i]=read();
		if(~b[i])p[b[i]]=i; 
	}
	for(int i=1;i<=n;i++)b[i]=p[i],vis1[b[i]]=1,p[i]=vis[i]=0;
	int cnt=0;
	for(int i=1;i<=min(s+1,n);i++){cnt+=!vis1[a[i]],vis[a[i]]=1;}
	int ans=1;
	for(int i=1;i<=n;i++)
	{
		if(b[i]){if(!vis[b[i]])return puts("0"),void();}
		else
		{
			ans=1ll*ans*cnt%mod;
			if(cnt)cnt--;
		}
		if(i+s<n)cnt+=!vis1[a[i+s+1]],vis[a[i+s+1]]=1;
	}
	printf("%d\n",ans);
}
int main()
{
	int T=read();
	while(T--)sol();
	return 0;
}

F

感觉这种题一直不是很会啊。

发现每次操作不会改变相邻元素无序二元组的集合,然后 \(a_1,a_n\) 不变,事实上这是 \(a\) 能变成 \(b\) 的充要条件。

必要性显然,充分性还不会证。

充分性:按照官方 Editorial 建图,那么就是要证明通过翻转这些边可以获得所有的合法欧拉通路(起点终点固定)。

然后考虑到欧拉通路的过程就是不断的环套环,整个环翻转边,所以证毕?(感觉是这样)

构造方式就是一个一个来,如果 \(a_{i+1}\)\(b_{i+1}\) 不一样,就找一下 \(a\) 里面的(\(i\) 后面)相邻的 \(a_{i}a_{i+1}\) 或者 \(a_{i+1}a_i\)。后者直接 reverse 过来,前者需要从 \(i\) 到这个位置之间 reverse 一下变成后者,然后按前者的操作来。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
const int N=510;
int a[N],b[N];
int vis[N];
vector<pii> ans;
void rev(int l,int r){reverse(a+l,a+r+1),ans.pb(mp(l,r));}
void sol()
{
	ans.clear();
	int n=read();
	vector<pii> va,vb;
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=n;i++)b[i]=read();
	for(int i=1;i<n;i++)va.pb(mp(min(a[i],a[i+1]),max(a[i],a[i+1])));
	for(int i=1;i<n;i++)vb.pb(mp(min(b[i],b[i+1]),max(b[i],b[i+1])));
	sort(va.begin(),va.end()),sort(vb.begin(),vb.end());
	if(a[1]!=b[1]||a[n]!=b[n]||va!=vb)return puts("NO"),void();
	for(int i=1;i<n;i++)
	{
		if(a[i+1]==b[i+1])continue;
		int pos=-1;
		for(int j=i;j<n;j++)if(a[j]==b[i+1]&&a[j+1]==b[i]){pos=j;break;}
		if(~pos){rev(i,pos+1);continue;}
		for(int j=i;j<n;j++)if(a[j]==b[i]&&a[j+1]==b[i+1]){pos=j;break;}
		memset(vis,-1,sizeof(vis));
		for(int j=i;j<=pos;j++)vis[a[j]]=j;
		for(int j=pos+1;j<=n;j++)if(~vis[a[j]]){pos=j;break;}
		if(!~pos)assert(0);
		rev(vis[a[pos]],pos),i--;
	}
	puts("YES");
	printf("%d\n",(int)ans.size());
	for(auto it:ans)printf("%d %d\n",it.fi,it.se);
}
int main()
{
	int T=read();
	while(T--)sol();
	return 0;
}
posted @ 2022-06-29 16:57  zzt1208  阅读(79)  评论(0编辑  收藏  举报