Pbri

Codeforces Global Round 15(缺I)

Codeforces Global Round 15(缺I)

A

排序后看有多少个位置与初始位置不一样即可。

\(code\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#define FUP(i,x,y) for(int i=(x);i<=(y);i++)
#define FDW(i,x,y) for(int i=(x);i>=(y);i--)
#define FED(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define pr pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define fi first
#define se second
#define MAXN 100010
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define ll long long
#define db double
using namespace std;
int read()
{
	int w=0,flg=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-'){flg=-1;}ch=getchar();}
	while(ch<='9'&&ch>='0'){w=w*10+ch-'0',ch=getchar();}
	return w*flg;
}
int T;
int n,ans;
char s[MAXN],t[MAXN];
void solve()
{
	n=read(),ans=0;
	scanf("%s",s+1);
	FUP(i,1,n) t[i]=s[i];
	sort(t+1,t+n+1);
	FUP(i,1,n) if(s[i]==t[i]) ans++;
	printf("%d\n",n-ans);
}
int main(){
	T=read();
	while(T--) solve();
	return 0;
}

B

虽然胜利不具有传递性,但排序后不在第一位的一定不是胜者。所以cmp的写法就是直接比较胜利条件,最后check第一位的人是否胜利即可。

\(code\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#define FUP(i,x,y) for(int i=(x);i<=(y);i++)
#define FDW(i,x,y) for(int i=(x);i>=(y);i--)
#define FED(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define pr pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define fi first
#define se second
#define MAXN 50010
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define ll long long
#define db double
using namespace std;
int read()
{
	int w=0,flg=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-'){flg=-1;}ch=getchar();}
	while(ch<='9'&&ch>='0'){w=w*10+ch-'0',ch=getchar();}
	return w*flg;
}
int T;
struct xuanshou{
	int a[5],id;
}p[MAXN];
bool cmp(xuanshou x,xuanshou y)
{
	int sum=0;
	FUP(i,0,4) if(x.a[i]<y.a[i]) sum++;
	return sum>=3;
}
int n;
void solve()
{
	n=read();
	FUP(i,1,n)
	{
		FUP(j,0,4) p[i].a[j]=read();
		p[i].id=i;
	}
	sort(p+1,p+n+1,cmp);
	FUP(i,2,n)
	{
		if(!cmp(p[1],p[i]))
		{
			puts("-1");
			return;
		}
	}
	printf("%d\n",p[1].id);
}
int main(){
	T=read();
	while(T--) solve();
	return 0;
}

C

考虑没有实现给定的弦的情况就是点 \(i\) 与点 \(i+n\) 相连。如果有弦,那么这条弦能做出的最大的贡献就是小的半圆里每条边都往外连,那么上述方案显然也满足这个条件。

\(code\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <vector>
#define FUP(i,x,y) for(int i=(x);i<=(y);i++)
#define FDW(i,x,y) for(int i=(x);i>=(y);i--)
#define FED(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define pr pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define fi first
#define se second
#define MAXN 1010
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define ll long long
#define db double
using namespace std;
int read()
{
	int w=0,flg=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-'){flg=-1;}ch=getchar();}
	while(ch<='9'&&ch>='0'){w=w*10+ch-'0',ch=getchar();}
	return w*flg;
}
int T;
bool vis[MAXN];
int n,K,ans;
vector<pr >ed;
vector<int>pot;
int ck(pr a,pr b)
{
	if(a.fi>b.fi) swap(a,b);
	return (b.fi>a.fi&&b.fi<a.se&&b.se>a.se);
}
void solve()
{
	memset(vis,0,sizeof(vis));
	ed.clear(),pot.clear();
	ans=0;
	n=read(),K=read();
	FUP(i,1,K)
	{
		int u=read(),v=read();
		if(u>v) swap(u,v);
		vis[u]=vis[v]=true;
		ed.push_back(mkp(u,v));
	}
	FUP(i,1,2*n) if(!vis[i]) pot.push_back(i);
	//printf("size=%d\n",(int)(pot.size()));
	FUP(i,0,(int)(pot.size())/2-1) ed.push_back(mkp(pot[i],pot[i+n-K]));
	FUP(i,0,n-1) FUP(j,i+1,n-1) ans+=ck(ed[i],ed[j]);
	printf("%d\n",ans);
}
int main(){
	T=read();
	while(T--) solve();
	return 0;
}

D

考虑如果我们的 \(b\) 数组可以有 \(n+1\) 个,那么我们直接做前缀和数组就好了。如果这 \(n\) 个数中存在两个没有交的集合,满足两个集合的元素之和是相等的,那么我们就可以忽略其中一个集合构造,先把另一个的前缀和数组放上,然后再把忽略的那个集合中的前 \(s-1\) 个数的前缀和数组放进去(假设有 \(s\) 个元素),然后再把剩下的放进去。然后最后那个数,因为两个集合的和相等,那么加上它的数一定已经出现过了。所以直接暴力枚举两个集合即可。

\(code\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#define FUP(i,x,y) for(int i=(x);i<=(y);i++)
#define FDW(i,x,y) for(int i=(x);i>=(y);i--)
#define FED(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define pr pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define fi first
#define se second
#define MAXN 100010
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define ll long long
#define db double
using namespace std;
int read()
{
	int w=0,flg=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-'){flg=-1;}ch=getchar();}
	while(ch<='9'&&ch>='0'){w=w*10+ch-'0',ch=getchar();}
	return w*flg;
}
int T;
int n,a[20],id[20];
bool ck(int cur,int sum1,int sum2)
{
	if(sum1==sum2&&cur) return true;
	if(cur==n) return false;
	cur++;
	FUP(i,cur,n)
	{
		if(!id[i])
		{
			id[i]=1;
			bool tmp=ck(i,sum1+a[i],sum2);
			id[i]=0;
			if(tmp) return true;
		}
	}
	FUP(i,cur,n)
	{
		if(!id[i])
		{
			id[i]=2;
			bool tmp=ck(i,sum1,sum2+a[i]);
			id[i]=0;
			if(tmp) return true;
		}
	}
	return false;
}
void solve()
{
	n=read();
	FUP(i,1,n) a[i]=abs(read());
	sort(a+1,a+n+1);
	if(a[1]==0)
	{
		puts("YES");
		return;
	}
	if(ck(0,0,0))
	{
		puts("YES");
		return;
	}
	puts("NO");
}
int main(){
	T=read();
	while(T--) solve();
	return 0;
}

E

我们如果按 \(\left\lceil\dfrac{n}{k-1}\right\rceil\) 个颜色分一组,相邻两组内不存在两种颜色使得他们的答案区间有交,那么显然每个位置只被覆盖了一次。接下来我们思考怎么分组:一开始我们按照每个数第二次出现的位置从小到大排序,然后我们把前 \(\left\lceil\dfrac{n}{k-1}\right\rceil\) 个颜色的区间确定下,然后把这段区间删除。这样其他的颜色最多只被删除了一个,因为如果删除了多个说明第二个在前面,然而我们已经排序过了,所以最多只有一个在里面。然后再剩下的射线和剩下的颜色里面重复这个操作。因为一个元素出现了 \(k\) 次,然后进行一些细节上的运算可以证明一定存在解。

\(code\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#define FUP(i,x,y) for(int i=(x);i<=(y);i++)
#define FDW(i,x,y) for(int i=(x);i>=(y);i--)
#define FED(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define pr pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define fi first
#define se second
#define MAXN 110
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define ll long long
#define db double
using namespace std;
int read()
{
	int w=0,flg=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-'){flg=-1;}ch=getchar();}
	while(ch<='9'&&ch>='0'){w=w*10+ch-'0',ch=getchar();}
	return w*flg;
}
int mat[MAXN][MAXN],tot[MAXN];
bool vis[MAXN];
int n,K,d,ans[MAXN][2];
struct node{
	int id,pos;
}p[MAXN];
bool cmp(node x,node y){return x.pos<y.pos;}
int main(){
	n=read(),K=read(),d=(n+K-2)/(K-1);
	FUP(i,1,n*K)
	{
		int a=read();
		mat[a][++tot[a]]=i; 
	}
	/*FUP(i,1,n)
	{
		FUP(j,1,K) printf("%d ",mat[i][j]);
		puts("");
	}*/
	FUP(i,1,INF)
	{
		int cnt=0;
		FUP(j,1,n)
		{
			if(vis[j]) continue;
			cnt++;
			p[cnt].id=j,p[cnt].pos=mat[j][i+1];
		}
		if(!cnt) break;
		sort(p+1,p+cnt+1,cmp);
		FUP(j,1,d)
		{
			//printf("id=%d pos=%d\n",p[j].id,p[j].pos);
			vis[p[j].id]=true;
			ans[p[j].id][0]=mat[p[j].id][i],ans[p[j].id][1]=mat[p[j].id][i+1];
		}
	}
	FUP(i,1,n) printf("%d %d\n",ans[i][0],ans[i][1]);
	return 0;
}

F

显然经过一个门之后这个门的状态会变成 \(1\) ,令 \(re_i\) 表示第 \(i\) 扇门的状态是 \(1\) 时,我们需要多久经过它,这样每个门就独立了。然后我们直接二分出传送回去后第一个遇到的位置,然后因为这些都是经历过的,所以他们的状态都是 \(1\) ,然后用前缀和优化求出经过这些门的状态就好了。然后最后计算 \(ans\) 只需要把初始状态是 \(1\) 的门的答案加起来就好了。

\(code\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#define FUP(i,x,y) for(int i=(x);i<=(y);i++)
#define FDW(i,x,y) for(int i=(x);i>=(y);i--)
#define FED(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define pr pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define fi first
#define se second
#define MAXN 200010
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-9
#define MOD 998244353
#define ll long long
#define db double
using namespace std;
int read()
{
	int w=0,flg=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-'){flg=-1;}ch=getchar();}
	while(ch<='9'&&ch>='0'){w=w*10+ch-'0',ch=getchar();}
	return w*flg;
}
int n;
struct door{
	int x,y,op;
}p[MAXN];
ll ans,re[MAXN],sum[MAXN];
int main(){
	n=read();
	FUP(i,1,n) p[i].x=read(),p[i].y=read(),p[i].op=read();
	ans=(p[n].x+1)%MOD;
	FUP(i,1,n)
	{
		re[i]=(p[i].x-p[i].y)%MOD;
		int l=0,r=i-1,pos=0;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			if(p[mid].x<p[i].y) pos=mid,l=mid+1;
			else r=mid-1;
		}
		re[i]=((re[i]+sum[i-1])%MOD-sum[pos]+MOD)%MOD;
		sum[i]=(sum[i-1]+re[i])%MOD;
	}
	FUP(i,1,n) if(p[i].op) ans=(ans+re[i])%MOD;
	printf("%lld\n",ans);
	return 0;
}

G

考虑这是个类似排序网络的东西,然后排序网络的经典结论是只要对所有的 \(01\) 串都成立那么结果成立。朴素的想法是我们枚举所有的 \(01\) 串然后暴力check,但是我们发现对于第一次排序,除了这些位置集合外的位置是没有意义的,也就是说对于很多的 \(01\) 串的第一次排序进行的操作是相同的,同时我们发现,我们只关心这些位置中 \(0\) 的数量和 \(1\) 的数量,我们不关心他们的位置,因为排序后就与初始位置无关了。所以我们只需要枚举有多少个 \(0\) 和多少个 \(1\) ,排序后放在这些位置上。对于接下来的排序,这些位置集合中有的我们已经确定放了什么数了,有的位置我们还没有确定,那么我们继续去枚举这些没有确定的位置中有多少个 \(0\) 和有多少个 \(1\) ,最后我们只需要判断如果有位置没被排序或者在枚举到现在的情况下check失败。

\(code\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#define FUP(i,x,y) for(int i=(x);i<=(y);i++)
#define FDW(i,x,y) for(int i=(x);i>=(y);i--)
#define FED(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define pr pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define fi first
#define se second
#define MAXN 100010
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define ll long long
#define db double
using namespace std;
int read()
{
	int w=0,flg=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-'){flg=-1;}ch=getchar();}
	while(ch<='9'&&ch>='0'){w=w*10+ch-'0',ch=getchar();}
	return w*flg;
}
int n,K,len[11],a[11][50],re[50];
void dfs(int cur)
{
	/*printf("cur=%d :",cur);
	FUP(i,1,n) printf("%d ",re[i]);
	puts("");*/
	if(cur==K)
	{
		FUP(i,1,n)
		{
			if(re[i]==-1||re[i]<re[i-1])
			{
				puts("REJECTED");
				exit(0);
			}
		}
		return;
	}
	int tmp[50];
	cur++;
	int cntxy=0,cntdy=0,cntwz=0;
	FUP(i,1,len[cur])
	{
		if(re[a[cur][i]]==-1) cntwz++;
		if(re[a[cur][i]]==0) cntxy++;
		if(re[a[cur][i]]==1) cntdy++;
	}
	FUP(i,1,cntxy) re[a[cur][i]]=0;
	FUP(i,cntxy+1,len[cur]) re[a[cur][i]]=1;
	FUP(i,1,n) tmp[i]=re[i];
	dfs(cur);
	FUP(i,1,cntwz)
	{
		FUP(j,1,n) re[j]=tmp[j];
		re[a[cur][i+cntxy]]=tmp[a[cur][i+cntxy]]=0;
		dfs(cur);
	}
}
int main(){
	n=read(),K=read();
	FUP(i,1,K)
	{
		len[i]=read();
		FUP(j,1,len[i]) a[i][j]=read();
	}
	if(n==1)
	{
		puts("ACCEPTED");
		return 0;
	}
	FUP(i,1,n) re[i]=-1;
	dfs(0);
	puts("ACCEPTED");
	return 0;
}

H

牛逼题。设这个矩形有 \(h\) 行点, \(w\) 列点,我们先求出这个矩形的面积设为 \(w\times h=S\),即把每一个位置都问一下。然后令 \(f(x)\) 表示问第 \(x,2x,3x...\) 行的答案。那么有 \(f(x)\times x=S\Leftrightarrow x|h\) 。然后我们二分出 \(h\) 的因子中最大的 \(2\) 的幂,然后我们发现设 \(2^r\)\(h\) 的因子中最大的 \(2\) 的幂,那么 \(|2\times f(2^{r+1})-f(2^r)|=w\) ,然后因为 \(n\) 不超过 \(200\) ,所以 \(f(2^8)=0\) ,然后 \(f(2^0)\) 一开始我们已经求出来了,总共 \(7\) 个数的二分层数正好是 \(3\) ,然后二分过程中我们必然已经求出来 \(f(2^{r+1})\) 了,所以我们就可以求出 \(w\) 了,因为我们知道面积,所以也知道 \(h\) 了。

\(code\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#define FUP(i,x,y) for(int i=(x);i<=(y);i++)
#define FDW(i,x,y) for(int i=(x);i>=(y);i--)
#define FED(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define pr pair<int,int>
#define mkp(a,b) make_pair(a,b)
#define fi first
#define se second
#define MAXN 100010
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define ll long long
#define db double
using namespace std;
int read()
{
	int w=0,flg=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-'){flg=-1;}ch=getchar();}
	while(ch<='9'&&ch>='0'){w=w*10+ch-'0',ch=getchar();}
	return w*flg;
}
int f(int d)
{
	printf("? %d\n",200/d*200);
	for(int i=d;i<=200;i+=d) FUP(j,1,200) printf("%d %d ",i,j);
	puts("");
	fflush(stdout);
	return read();
}
int w[9],base[9]={1,2,4,8,16,32,64,128,256},re;
int main(){
	w[0]=f(base[0]);
	int l=1,r=7;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		w[mid]=f(base[mid]);
		if(w[mid]*base[mid]==w[0]) re=mid,l=mid+1;
		else r=mid-1;
	}
	int b=abs(w[re]-2*w[re+1])-1,a=w[0]/(b+1)-1;
	printf("! %d",a*2+b*2);
	return 0;
}
posted @ 2021-09-26 21:42  Pbri  阅读(68)  评论(0编辑  收藏  举报