Codeforces Global Round 22(持续更新)

Preface

这场不知道为什么打的就是一坨屎,B和C都G了好久后来才发现都是贼弱智的错误

结果好不容易找出来D没时间了,写了个假算法,直接掉大分


A. Glory Addicts

不难发现交错来放把每种type的前\(\min(c_1,c_2)\)大的都强化即可,\(c_1,c_2\)是两种type的数量

注意\(c_1=c_2\)时最小的那个技能不能被强化,需要特别注意

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int t,n,c1,c2,a[N],b[N],x[N],y[N]; long long ans;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d",&n),c1=c2=ans=0,i=1;i<=n;++i) scanf("%d",&a[i]);
		for (i=1;i<=n;++i) if (scanf("%d",&b[i]),ans+=b[i],a[i]) y[++c2]=b[i]; else x[++c1]=b[i];
		if (sort(x+1,x+c1+1),sort(y+1,y+c2+1),c1==c2)
		{
			ans*=2LL; printf("%lld\n",ans-min(x[1],y[1]));
		} else
		{
			for (i=1;i<=min(c1,c2);++i) ans+=x[c1-i+1]+y[c2-i+1]; printf("%lld\n",ans);
		}
	}
	return 0;
}

B. Prefix Sum Addicts

不难发现用这\(k\)\(s_i\)的信息我们可以确定下后\(k-1\)个数的准确值,并且知道前\(n-k+1\)个数的和

那么先验证后面\(k-1\)个数的合法性,然后考虑前面的\(n-k+1\)个数的填法,要求在满足不降条件下\(a_{n-k+1}\)尽量小

显然直接均分时最优的,但实际写的时候有一些边界的细节需要注意,搞了半天发现是\(n=1\)的情况没处理好

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int t,n,s[N],a[N],k;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d%d",&n,&k),i=n-k+1;i<=n;++i) scanf("%d",&s[i]);
		if (k==1) { puts("Yes"); continue; }
		for (i=n;i>n-k+1;--i) a[i]=s[i]-s[i-1]; if (n==k) a[1]=s[1];
		bool flag=1; for (i=n;i>n-k+2&&flag;--i) if (a[i]<a[i-1]) flag=0;
		if (n==k) flag&=(a[1]<=a[2]); if (!flag) { puts("No"); continue; }
		if (n==k) { puts("Yes"); continue; }
		int left=s[n-k+1],cur; if (left>0) cur=(left-1)/(n-k+1)+1; else cur=-((-left)/(n-k+1));
		puts(cur<=a[n-k+2]?"Yes":"No");
	}
	return 0;
}

C. Even Number Addicts

我真的是服了开了c[2]的数组,结果在清空的时候写了c[1]=c[2]=0,直接WA爆

刚开始有一个大概的用\(0/1\)个数的奇偶性来做的方法,结果只讨论出总和为偶数的情况,后面的越想脑子越乱就急了

后面本来想打个暴力来辅助找规律的,结果看了一眼数据范围不是暴力随便过吗,真想抽自己一个大耳光子

从此立下flag,以后写题之前必先看数据范围

其实就是一个很简单的记忆化搜索,我们设状态\((x,y,z,opt)\)表示局面上剩下的奇数个数为\(x\),剩下的偶数个数为\(y\)Alice已经拿走的数的和的奇偶性为\(z\),当前操作的人是\(opt\)时局面时必胜态还是必败态

转移随便写写就好了,若当前状态的所有后继状态都是必胜态那它就是必败态,否则若存在一个必败态它就是必胜态

复杂度\(O(n^2)\),关于找性质的做法可以看这里

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
int t,n,a[N],c[2],f[N][N][2][2]; 
inline bool DFS(CI x,CI y,CI z,CI opt) //num_odd,num_even,num_A_taken opt=0:A opt=1:B
{
	if (~f[x][y][z][opt]) return f[x][y][z][opt];
	if (!x&&!y) return f[x][y][z][opt]=z==opt;
	int nxt=0; if (x>0) nxt|=!DFS(x-1,y,opt==0?z^1:z,opt^1);
	if (y>0) nxt|=!DFS(x,y-1,z,opt^1);
	return f[x][y][z][opt]=nxt;
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t),memset(f,-1,sizeof(f));t;--t)
	{
		RI i; for (scanf("%d",&n),c[1]=c[0]=0,i=1;i<=n;++i) scanf("%d",&a[i]),++c[a[i]&1];
		puts(DFS(c[1],c[0],0,0)?"Alice":"Bob");
	}
	return 0;
}

D. Permutation Addicts

首先我们很容易推出关于\(k\)的性质:

  • \(i\le k\),则\(b_i>i\)
  • \(i>k\),则\(b_i<i\)

因此我们只要找到最大的那个满足\(b_i>i\)\(i\),令其为\(k\)即可

接下来我们发现对于每一组\((i,b_i)\)关系,其实就是强制要求\(b_i\)出现在\(i\)之前

因此我们可以直接建立有向边\(b_i\to i\),由于加入了点\(0\)和点\(n+1\),并且这两个点中一定存在一个点是独立的

因此由于图的点数为\(n+1\),边数为\(0\),因此图是一棵树,不难发现我们直接BFS一遍就可以得出答案了

同层的叶子节点对答案没有影响,可以按照任意顺序遍历

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#define RI register int
#define CI const int&
#define pb push_back
using namespace std;
const int N=100005;
vector <int> v[N],q; int t,n,k,b[N];
inline bool cmp(CI x,CI y)
{
	return v[x].size()<v[y].size();
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d",&n),k=0,i=1;i<=n;++i)
		{
			if (scanf("%d",&b[i]),i<b[i]) k=i; v[b[i]].pb(i);
		}
		q.clear(); q.pb(v[0].size()?0:n+1);
		for (i=0;i<q.size();++i)
		{
			int now=q[i]; sort(v[now].begin(),v[now].end(),cmp);
			for (int to:v[now]) q.pb(to);
		}
		if (q.size()!=n+1) puts("-1"); else
		{
			for (printf("%d\n",k),i=1;i<=n;++i) printf("%d%c",q[i]," \n"[i==n]);
		}
		for (i=0;i<=n+1;++i) v[i].clear();
	}
	return 0;
}
posted @ 2022-10-07 00:12  空気力学の詩  阅读(93)  评论(0)    收藏  举报