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;
}