Pinely Round 4 (Div. 1 + Div. 2)

Preface

难得地有直觉的一场,50min 过了前 5 题后形式大好,然后 F 也一眼看出了有个斐波那契的上界

结果写了个暴力判断交上去一直挂,前面一直以为是一定有解的阈值设错了,没想到挂了好几发后发现暴力漏了一种 Case,真是唐完了


A. Maximize the Last Element

不难发现只有奇数位置上的数可以保留下来

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=105;
int t,n,a[N];
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);
		int mx=0; for (i=1;i<=n;i+=2) mx=max(mx,a[i]);
		printf("%d\n",mx);
	}
	return 0;
}

B. AND Reconstruction

对于每一位分别考虑,若 \(b_i\) 该位为 \(1\),则 \(a_i\)\(a_{i+1}\) 的这一位都必须是 \(1\);然后默认其余的都为 \(0\) 最后检验下是否合法即可

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=100005;
int t,n,a[N],b[N],c[N];
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i,j; for (scanf("%d",&n),i=1;i<n;++i) scanf("%d",&b[i]);
		for (i=1;i<=n;++i) a[i]=0; bool flag=1;
		for (j=0;j<30&&flag;++j)
		{
			for (i=1;i<=n;++i) c[i]=0;
			for (i=1;i<n;++i)
			if ((b[i]>>j)&1) c[i]=c[i+1]=1;
			for (i=1;i<n;++i)
			if (!((b[i]>>j)&1)&&c[i]&&c[i+1]) { flag=0; break; }
			for (i=1;i<=n;++i) if (c[i]) a[i]|=(1<<j);
		}
		if (!flag) { puts("-1"); continue; }
		for (i=1;i<n;++i) assert((a[i]&a[i+1])==b[i]);
		for (i=1;i<=n;++i) printf("%d%c",a[i]," \n"[i==n]);
	}
	return 0;
}

C. Absolute Zero

神秘构造题,看完题面就感觉是个那一堆 \(2\) 的幂次来构造,还在想怎么会有无解的情况

后面仔细一想发现如果初始序列中又有奇数又有偶数,则每次操作后序列仍然是有奇有偶的,因此永远不可能全为 \(0\)

否则手玩一波后会发现对于偶数就用形如 \(2^{29},2^{28},\dots,2^1,1,1\) 这样的构造方式;奇数就用形如 \(2^{29},2^{28},\dots,2^1,1\) 这样的构造方式即可

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=200005;
int t,n,a[N];
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; int c[2]={0,0};
		for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]),++c[a[i]&1];
		if (c[0]>0&&c[1]>0) { puts("-1"); continue; }
		if (c[0]>0)
		{
			puts("31");
			for (i=29;i>=0;--i) printf("%d ",1<<i);
			puts("1");
		} else
		{
			puts("30");
			for (i=29;i>=0;--i) printf("%d%c",1<<i," \n"[i==0]);
		}
	}
	return 0;
}

D. Prime XOR Coloring

很需要直觉的一个题,不然可能想半天想不出来

由于自然数中最小的不是质数的数是 \(4\),因此考虑让同色的数之间的异或值都是 \(4\) 的倍数就可以构造一种符号要求的做法

显然将所有数按照它们模 \(4\) 的余数分组,同组数染一种颜色即可,这样组内任意两数异或值都是 \(4\) 的倍数

最后对于数比较小的情况,把样例抄下来就完事

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=200005;
int t,n;
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		scanf("%d",&n);
		if (n==1) puts("1\n1"); else
		if (n==2) puts("2\n1 2"); else
		if (n==3) puts("2\n1 2 2"); else
		if (n==4) puts("3\n1 2 2 3"); else
		if (n==5) puts("3\n1 2 2 3 3"); else
		{
			puts("4");
			for (RI i=1;i<=n;++i) printf("%d%c",i%4+1," \n"[i==n]);
		}
	}
	return 0;
}

E. Coloring Game

思路很简单的一个题,感觉只有正常的 Div.2 D 的难度

首先考虑来个黑白染色,如果给出的图不是二分图那么选先手,保证每次都给 1 2 两种颜色,此时一定必胜

否则如果给出的图是二分图就选后手,不妨设原图中的黑点对应颜色 \(1\),白点对应颜色 \(2\)

对于交互器每次给出的两种颜色,如果存在颜色 \(1/2\) 且它们对应的点还没有被染色,那么就直接对应地染色

否则如果不存在上述情况,则必然存在一种颜色已经把对应的点涂完了,那剩下没涂完的点都用颜色 \(3\) 即可

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=10005;
int t,n,m,x,y,col[N]; bool flag; vector <int> v[N],c[2];
inline void DFS(CI now)
{
	for (auto to:v[now])
	if (col[to]==-1) col[to]=col[now]^1,DFS(to);
	else if (col[to]==col[now]) flag=0;
}
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; scanf("%d%d",&n,&m);
		for (i=1;i<=n;++i) v[i].clear(),col[i]=-1;
		for (i=1;i<=m;++i) scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
		flag=1; c[0].clear(); c[1].clear();
		for (i=1;i<=n;++i) if (col[i]==-1) col[i]=0,DFS(i);
		if (!flag)
		{
			printf("Alice\n"); fflush(stdout);
			for (i=1;i<=n;++i)
			{
				printf("1 2\n"); fflush(stdout);
				int x,y; scanf("%d%d",&x,&y);
			}
		} else
		{
			printf("Bob\n"); fflush(stdout);
			for (i=1;i<=n;++i) c[col[i]].push_back(i);
			for (i=1;i<=n;++i)
			{
				int x,y; scanf("%d%d",&x,&y);
				if ((x==1||y==1)&&!c[0].empty())
				{
					printf("%d 1\n",c[0].back());
					c[0].pop_back(); fflush(stdout); continue;
				}
				if ((x==2||y==2)&&!c[1].empty())
				{
					printf("%d 2\n",c[1].back());
					c[1].pop_back(); fflush(stdout); continue;
				}
				if (!c[0].empty())
				{
					printf("%d 3\n",c[0].back());
					c[0].pop_back(); fflush(stdout);
				} else
				{
					printf("%d 3\n",c[1].back());
					c[1].pop_back(); fflush(stdout);
				}
			}
		}
	}
	return 0;
}

F. Triangle Formation

神秘观察题,发现一定有解的下界后就很简单了

考虑如果在一堆棍子里找一个三角形,那么排序之后找相邻的三个一定最优

因此如果要构造一个三角形都找不到的数据,则木棍的长度一定形如斐波那契数列

简单计算发现第 \(44\) 个斐波那契数大于 \(10^9\),然后就说明当区间长度 \(>50\) 时一定有解

现在考虑怎样快速判断能否找到两个三角形,不妨先给所有数从小到大排序,并钦定第一个三角形的最长边小于等于第二个三角形的最长边

枚举第一个三角形的最长边,分以下三种情况讨论:

  • 第二个三角形三条边都在当前这条边后面,这个可以预处理每个后缀的信息
  • 第二个三角形较长的两条边都在当前这条边后面,这个只需要求出后缀中差值最小的两条边,然后每次在前面找一个是否大于这个差值的边
  • 第二个三角形最长的一条边在当前这条边后面,此时需要找到前面还没被用的最长的两条边,和之后的最短的边比较下即可

那么我们再枚举第一个三角形的次长边,然后用一个 two pointers 扫一下即可,单组询问复杂度 \(\min^2(50,r-l+1)\)

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=100005,INF=1e9;
int n,q,a[N],l,r;
signed main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (scanf("%d%d",&n,&q),i=1;i<=n;++i) scanf("%d",&a[i]);
	while (q--)
	{
		scanf("%d%d",&l,&r);
		if (r-l+1>50) { puts("YES"); continue; }
		vector <int> vec;
		for (i=l;i<=r;++i) vec.push_back(a[i]);
		sort(vec.begin(),vec.end());
		vector <int> suf(vec.size(),0),d(vec.size(),INF);
		int mnp=INF,mxp=-INF;
		for (i=0;i+2<vec.size();++i)
		if (vec[i]+vec[i+1]>vec[i+2])
		suf[i]=1,mnp=min(mnp,i),mxp=max(mxp,i);
		if (mxp-mnp>=3) { puts("YES"); continue; }
		for (i=vec.size()-1;i>=1;--i) suf[i-1]|=suf[i];
		for (i=vec.size()-2;i>=0;--i)
		d[i]=min(d[i+1],vec[i+1]-vec[i]);
		bool flag=0;
		for (i=2;i+1<vec.size()&&!flag;++i)
		{
			for (RI j=i-1,k=0;k<j;--j)
			{
				while (k<j&&vec[k]+vec[j]<=vec[i]) ++k;
				if (k>=j) continue;
				if (suf[i+1]) { flag=1; break; }
				int mxp=i-1;
				while (mxp==j||mxp==k) --mxp;
				if (mxp>=0&&vec[mxp]>d[i+1]) { flag=1; break; }
				if (mxp<=0) continue;
				int smxp=mxp-1;
				while (smxp==j||smxp==k) --smxp;
				if (smxp>=0&&vec[smxp]+vec[mxp]>vec[i+1]) { flag=1; break; }
			}
		}
		puts(flag?"YES":"NO");
	}
	return 0;
}

Postscript

后面的题银牌✌比赛时快 2h 都没做出来,说明肯定不是我能做的了,直接白兰

posted @ 2024-07-29 20:13  空気力学の詩  阅读(181)  评论(0编辑  收藏  举报