其他分享
首页 > 其他分享> > 【AtCoder】AtCoder Grand Contest 041 解题报告(开坑之时已至,目前只有$A,B,C$)

【AtCoder】AtCoder Grand Contest 041 解题报告(开坑之时已至,目前只有$A,B,C$)

作者:互联网

点此进入比赛

这里只是开个坑,然后把已经写掉的\(A,B,C\)题解先水一水,剩下的题目打算到时候再做吧。

\(A\):Table Tennis Training(点此看题面

大致题意: 有\(n\)个位置,一开始一对好朋友分别在\(a,b\)两个位置。每单位时间,二人可分别选择向左或向右走\(1\)个位置(若超出范围则保持不动),求二人至少要多少时间相遇。

不妨设\(a<b\),则可以进行如下分类讨论。

\(b-a\)为偶数

显然,此时二人只要向着对方走,只需\(\frac{b-a}2\)的时间即可相遇。

\(b-a\)为奇数

显然,此时必然是一个人走到\(1\)或\(n\),在那里等一回合使得二人间距离为偶数,然后再走到一起。

而且必然是\(a\)走到\(1\)或者\(b\)走到\(n\),因此我们再分类讨论:

综上所述,最短时间应为\(min(a,n-b+1)+\frac{b-a+1}2\)。

提交记录

神奇地\(CE\)了两发。。。(似乎是选错了语言,好像不能选Clang?)

然后一发就过了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define LL long long
#define swap(x,y) (x^=y^=x^=y)
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
LL n,a,b;
int main()
{
	scanf("%lld%lld%lld",&n,&a,&b);if(a>b&&swap(a,b),(a&1)==(b&1)) return printf("%lld",b-a>>1),0;//使a<b;处理偶数情况
	return printf("%lld",(b-a-1>>1)+min(a,n-b+1)),0;//处理奇数情况
}

\(B\):Voting Judges(点此看题面

大致题意: 有\(n\)个数,你需要进行\(m\)次操作,每次选择恰好\(v\)个数各加\(1\)。求有多少个数在\(m\)次操作后可能成为前\(p\)大的数。

可二分性≠要用二分做

显然这道题是具有可二分性的,因为如果一个数可以,那么比它大的数一定都可以。

但我们一定要用二分吗?事实上,我们直接枚举判断,也可以做到\(O(n)\)。

因此,具有可二分性的题目,不一定就要用二分做。

如何判断

考虑将所有数从大到小排序,设为\(a_{1\sim n}\),并令\(s_{1\sim n}\)为其前缀和。

假设我们当前判断\(a_i\)是否可能成为前\(p\)大的数,那么按照贪心的思想,我们只要让它刚好卡在第\(p\)个就可以了。

因此,我们可以把第\(i\)个数、最大的\(p-1\)个数(因为这\(p-1\)个数是无须超越的)、比\(i\)小的\(n-i+1\)个数(因为这些数怎么加都超不过第\(i\)个数)全都加上\(m\)。

则还剩下需要加的\(1\)的个数为:

\[max(v-p-(n-i),0)\times m \]

我们考虑求出把第\(p\sim i-1\)个数全都刚好加到\(a_i+m\),如果加不到或恰好加满说明当前答案可行,若有\(1\)剩余说明不可行。

那么需要多少个\(1\)呢?这时候前面记下的前缀和就派上用场了,需要的\(1\)的个数就是:

\[(i-p)\times (a_i+m)-(s_{i-1}-s_{p-1}) \]

似乎我们只要比较这个式子与前面式子的大小关系就能得出答案了,但这其实是有瑕疵的。

为什么呢?因为假如你有一个数原本就大于\(a_i+m\),难道你还能给它负数个\(1\),让它变小吗?

所以,我们要先判一下\(a_i+m\)是否大于等于\(a_p\),然后再进行上述判断。(闪指导就被这个坑了)

提交记录

第一发交完等待评测的时候,突然发现有个地方漏开\(long\ long\)了。

于是第一发果不其然\(WA\)了,开了\(long\ long\)重交了一发才过。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define LL long long
using namespace std;
int n,m,v,p,a[N+5];LL s[N+5];
I bool cmp(CI x,CI y) {return x>y;}//从大到小排序
int main()
{
	RI i;for(scanf("%d%d%d%d",&n,&m,&v,&p),i=1;i<=n;++i) scanf("%d",a+i);
	for(sort(a+1,a+n+1,cmp),i=1;i<=n;++i) s[i]=s[i-1]+a[i];//排序后求前缀和
	for(i=n;i>p;--i) if(a[i]+m>=a[p])//枚举答案,首先要使得加上m后大于等于第p个数
		if(1LL*max(v-p-(n-i),0)*m<=1LL*(a[i]+m)*(i-p)-(s[i-1]-s[p-1])) break;//用1去填平中间的坑
	return printf("%d",i),0;//输出答案(若始终没break则最后i恰好等于p)
}

\(C\):Domino Quality(点此看题面

大致题意: 有一张\(n\times n\)的网格图,你要摆上至少一个\(1\times 2\)的骨牌,使得各行各列覆盖其至少一格的骨牌个数皆相等。

注意:接下来开始的三部分都只是我的思路历程(勿喷),此题终题解只需看总结部分即可。

手玩一小时

这种构造题一般套路想想都是手玩->发现规律->切掉,怀着这样的想法,我就开始了暗无天日的手玩。。。

于是,大约一小时过去了,弱小的我和强大的闪指导依旧只画出了\(n=3,4,5\)的解。

而且,没有任何规律。。。

题解的辅助

没办法,只好去找了篇题解,看了看最终的规律似乎是:

于是我们从中得到了几点启发:

画去画去就困了,先睡个觉,明天再接着画。

自习课加成

果然,正如闪指导所言,在班里就能智商++,自习课更是有着极为优秀的加成。

第二天起来到班里,来机房前就无聊乱画(说起来今明两天是月考,因为停课逃掉了),结果突然就把\(n\)为偶数情况的规律画出来了?!

此时极为亢奋的我再接再厉,不到一分钟又画出了\(n=7\)?!

(顺便说一下,过于亢奋的我刚画完就兴冲冲地奔向了机房,到了之后发现画了图的草稿纸没带,结果凭借残余的记忆还又用了五六分钟才重新画出\(n=7\)的解。由此再次验证了闪指导的话的正确性,果然闪指导是我们的红太阳,他说的话都是真理!)

总结

好了,上面那一堆都是废话,接下来才是正经的结论。

大体上就是这样了,然后就是模拟模拟模拟。

提交记录

\(RE\)???仔细看了一遍代码,然后发现智障地写了这样一句:

return puts("-1");

\(WA\)???而且只\(WA\)一个点???

不断思索有什么单个数据是特殊的,最后发现挂在了\(9\)上(\(5+4\)),\(9\)中的\(4\)也是需要特判的,而我原本是把\(4\)单独拉出来特判的。所以只好又把\(4\)的情况放回了偶数大家庭。。。

然后终于过了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000
using namespace std;
int n,a[N+5];char s[N+5][N+5];
char s3[4][4]={"","aab","b.b","baa"};
char s5[6][6]={"","abba.","a..ab","bba.b","a.acc","abbaa"};
char s7[8][8]={"","aabbaa.","b..a..a","b..a..a","...baab","...bccb","abb...a","acc...a"};
char s4[5][5]={"","aaba","ccba","abcc","abaa"};
I void Draw(CI n)//模拟看起来很长,实际上仔细看下就发现三部分几乎一样,只有小变动而已(实际上我本来就基本上是复制粘贴的)
{
	RI i,j;if(n==4)//特判n=4
	{
		for(i=1;i<=4;++i) for(j=1;j<=4;++j) s[i][j]=s4[i][j-1];return;
	}
	if(n%6==0)
	{
		for(i=1;i<=n/6;++i)
			s[6*i-5][i]=s[6*i-4][i]=s[n-6*i+6][n-i+1]=s[n-6*i+5][n-i+1]='x',
			s[6*i-3][i]=s[6*i-2][i]=s[n-6*i+4][n-i+1]=s[n-6*i+3][n-i+1]='y',
			s[6*i-1][i]=s[6*i][i]=s[n-6*i+2][n-i+1]=s[n-6*i+1][n-i+1]='z';
		for(i=1;i<=n/3;++i)
			s[3*i-2][n/6+2*i-1]=s[3*i-2][n/6+2*i]='a',
			s[3*i-1][n/6+2*i-1]=s[3*i-1][n/6+2*i]='b',
			s[3*i][n/6+2*i-1]=s[3*i][n/6+2*i]='c';
	}
	if(n%6==2)
	{
		for(i=1;i<=n/6;++i)
			s[6*i-5][i]=s[6*i-4][i]=s[n-6*i+6][n-i+1]=s[n-6*i+5][n-i+1]='x',
			s[6*i-3][i]=s[6*i-2][i]=s[n-6*i+4][n-i+1]=s[n-6*i+3][n-i+1]='y',
			s[6*i-1][i]=s[6*i][i]=s[n-6*i+2][n-i+1]=s[n-6*i+1][n-i+1]='z';
		s[n-1][i]=s[n][i]=s[2][n-i+1]=s[1][n-i+1]='p';
		for(i=1;i<=n/3;++i)
			s[3*i-2][n/6+2*i-1]=s[3*i-2][n/6+2*i]='a',
			s[3*i-1][n/6+2*i-1]=s[3*i-1][n/6+2*i]='b',
			s[3*i][n/6+2*i]=s[3*i][n/6+2*i+1]='c';
		s[n-1][n/6+2*i-1]=s[n-1][n/6+2*i]='a',
		s[n][n/6+2*i-1]=s[n][n/6+2*i]='b';
	}
	if(n%6==4)
	{
		for(i=1;i<=n/6;++i)
			s[6*i-5][i]=s[6*i-4][i]=s[n-6*i+6][n-i+1]=s[n-6*i+5][n-i+1]='x',
			s[6*i-3][i]=s[6*i-2][i]=s[n-6*i+4][n-i+1]=s[n-6*i+3][n-i+1]='y',
			s[6*i-1][i]=s[6*i][i]=s[n-6*i+2][n-i+1]=s[n-6*i+1][n-i+1]='z';
		s[n-3][i]=s[n-2][i]=s[4][n-i+1]=s[3][n-i+1]='p',
		s[n-1][i]=s[n][i]=s[2][n-i+1]=s[1][n-i+1]='q';
		for(i=1;i<=n/3;++i)
			s[3*i-2][n/6+2*i-1]=s[3*i-2][n/6+2*i]='a',
			s[3*i-1][n/6+2*i]=s[3*i-1][n/6+2*i+1]='b',
			s[3*i][n/6+2*i]=s[3*i][n/6+2*i+1]='c';
		s[n][n/6+2*i-1]=s[n][n/6+2*i]='a';
	}
}
int main()
{
	RI i,j;if(scanf("%d",&n),n==2) return puts("-1"),0;//n=2输出-1
	if(n==3) {for(i=1;i<=3;++i) puts(s3[i]);return 0;}//特判n=3
	if(n==5) {for(i=1;i<=5;++i) puts(s5[i]);return 0;}//特判n=5
	if(n==7) {for(i=1;i<=7;++i) puts(s7[i]);return 0;}//特判n=7
	for(i=1;i<=n;++i) for(j=1;j<=n;++j) s[i][j]='.';//初始化点阵
	if(n&1) for(Draw(n-5),i=1;i<=5;++i) for(j=1;j<=5;++j) s[n-5+i][n-5+j]=s5[i][j-1];else Draw(n);//奇数转化为偶数,然后开始模拟画画
	for(i=1;i<=n;++i) puts(s[i]+1);return 0;//输出答案
}

标签:.....,AtCoder,bb,..,Contest,cc,....,开坑,define
来源: https://www.cnblogs.com/chenxiaoran666/p/AtCoderAGC041.html