ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-05-13 09:04:34  阅读:288  来源: 互联网

标签:..... AtCoder bb .. Contest cc .... 开坑 define


点此进入比赛

这里只是开个坑,然后把已经写掉的\(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\),因此我们再分类讨论:

  • \(a\)走到\(1\):\(a\)走到\(1\)并等待一回合共需要\(a\)的时间,此时\(b\)走到了\(b-a\),因此还需\(\frac{b-a-1}2\)的时间。总时间为\(a+\frac{b-a-1}2\)。
  • \(b\)走到\(n\):\(b\)走到\(n\)并等待一回合共需要\(n-b+1\)的时间,此时\(a\)走到了\(n-b+1+a\),因此还需\(\frac{b-a-1}2\)的时间。总时间为\((n-b+1)+\frac{b-a+1}2\)。

综上所述,最短时间应为\(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=3,5,7\),直接打表。
  • 对于\(n\)为偶数,若\(n=4\)则打表,否则规律显然。
  • 对于\(n\)为奇数,补一个\(n=5\)的答案转化为\(n\)为偶数。

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

  • 难怪我们没有找到任何规律,因为我们求出的这几个答案都是特殊情况。。。
  • 我们还需要手玩出\(n=7\)并发现\(n\)为偶数的规律,再去考虑怎么补上\(n=5\)的答案把奇数变成偶数,这又将是一个浩大的工程。

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

自习课加成

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

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

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

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

总结

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

  • 对于\(n=3,5,7\),直接打表。(可见代码)

  • 对于\(n\)为偶数,我的确是自己推出了一个统一的规律,但感觉把\(n\)分类为模\(6\)余\(0,2,4\)三种情况似乎更好理解、说明,也更好码(码量虽然大了点,但实际只是多按了几个\(Ctrl\ C+Ctrl\ V\)):

    \(n\%6=0\),如图所示:(由于我比较懒,图被吞了,直接用题目中的表示方法吧)

    x.aa......z.
    x.bb......z.
    y.cc......y.
    y...aa....y.
    z...bb....x.
    z...cc....x.
    .x....aa...z
    .x....bb...z
    .y....cc...y
    .y......aa.y
    .z......bb.x
    .z......cc.x
    

    我想图画出来后这规律应该就比较显然了吧。。。

    \(n\%6=2\),如图所示

    x.aa.......p..
    x.bb.......p..
    y..cc.......z.
    y...aa......z.
    z...bb......y.
    z....cc.....y.
    .x....aa....x.
    .x....bb....x.
    .y.....cc....z
    .y......aa...z
    .z......bb...y
    .z.......cc..y
    ..p.......aa.x
    ..p.......bb.x
    

    和\(n\%6=0\)很像,不是吗?事实上,仔细观察就发现仅仅是把所有"cc"右移了一格(可理解为"pp"的存在占据了"cc"原本的位置)。

    \(n\%6=4\),如图所示

    x.aa.........q..
    x..bb........q..
    y..cc........p..
    y...aa.......p..
    z....bb.......z.
    z....cc.......z.
    .x....aa......y.
    .x.....bb.....y.
    .y.....cc.....x.
    .y......aa....x.
    .z.......bb....z
    .z.......cc....z
    ..p.......aa...y
    ..p........bb..y
    ..q........cc..x
    ..q.........aa.x
    

    看完前两种情况就很好明白了,"pp"和"qq"占据了"bb"和"cc"原本的位置,使得"bb"和"cc"需要右移一格。

  • 对于\(n\)为奇数,我们需要这样画:

    **********.....
    **********.....
    **********.....
    **********.....
    **********.....
    **********.....
    **********.....
    **********.....
    **********.....
    **********.....
    ..........abba.
    ..........a..ab
    ..........bba.b
    ..........a.acc
    ..........abbaa
    

    其中"*"构成的矩阵表示\(n-5\)的答案,右下角为\(5\)的答案。

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

提交记录

\(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有