2021CCPC网络预选赛(第一场)赛后团队小结



比赛相关信息

比赛信息:

比赛名称: 2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛
组织方:杭州电子大学 && CCPC组委会
比赛形式:线上
赛制:ACM / 团体

队伍信息:

队名:高等数学半价出售
队长:魏道(题目思路、测试集)
队员1:王晨杰(主码手)
队员2:黄文豪(副码手、读题)

比赛过程回顾:


第1题

第2题

第3题

第4题

第5题

第6题

第7题

提交次数

3

0

0

0

0

1

0

首次提交时间

00:21:49

04:44:15






首A时间

01:03:43








第8题

第9题

第10题

第11题

第12题

第13题

提交次数

0

2

0

0

0

0

首次提交时间

02:08:58






首A时间

02:54:24






部分题解与小结

A. Cut The Wire

tag:

⇔模拟、⇔简单数论(冰雹数)

题意:

对无限多个路灯进行编号,从 \(1\) 一直到 \(+\infty\) 。

这些路灯互相有电线相连,规则是:

  • 若路灯编号 \(k\) 为奇数,则 \(k\) 和 \(3*k+1\) 相连。
  • 若路灯编号 \(k\) 为偶数,则 \(k\) 和 \(\frac{k}{2}\) 相连。

现在已知路灯编号 \(pos\) ,输出 \(pos\) 和 \(pos+1\) 号路灯间的电线数量。

一共 \(T(1\leq T\leq 10^5)\) 组询问。

思考过程:

组内讨论时,推这道题的公式推的比较混乱,在提交一次WA了之后,经过与打表数据细致的比对,发现公式无法正确计算得出“3的奇数次倍数”的正确答案,于是对于这一部分数据进行了特判。代码一并给出在下方【AC代码2】中,供大家惊醒参考。

在赛后复盘中,我们重新推演了公式,得到了这道题的正解。

正解:

经组内讨论,发现答案由四部分组成:

  • 位于 \(pos\) 号路灯之后的,编号为偶数的路灯,满足方程: \(\frac{x}{2} \leqslant pos\) 。
  • 位于 \(pos\) 号路灯之前的,编号为偶数的路灯,满足方程: \(x\geqslant pos+1\) 。
  • 位于 \(pos\) 号路灯之后的,编号为奇数的路灯,满足方程: \(x\leqslant pos\) 。
  • 位于 \(pos\) 号路灯之前的,编号为奇数的路灯,满足方程: \(3*x+1\geqslant pos+1\) 。

于是题目化简为求满足\(\begin{cases}pos+1\leqslant x\leqslant 2*pos & \text{ ,x为偶数 } \\ pos\leqslant 3*x\leqslant 3*pos & \text{ ,x为奇数 } \end{cases}\)的 \(x\) 的数量。

由简单数理推断,发现当 \(pos\) 为偶数时,答案为 \(\frac{pos}{2}+(pos-2)\mid 3+1\) ;当 \(pos\) 为奇数时,答案为 \(\frac{pos+1}{2}+pos\mid 3+1\) 。

AC代码1:

//A WIDA Project
#include<bits/stdc++.h>
using namespace std;
long long q,pos,ans;
int main(){
ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>q;
while(q--){
cin>>pos;
ans=0;
if(pos%2==0){
ans+=pos/2;
ans+=(pos-2)/3+1;
}else{
ans+=(pos+1)/2;
ans+=pos/3+1;
}
cout<<ans<<endl;
}
return 0;
}


AC代码2:

//team2699
#include<bits/stdc++.h>
using namespace std;
long long q,pos,ans;
int main(){
ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>q;
while(q--){
cin>>pos;
ans=0;
if (pos%2==0){
ans+=pos/2;
ans+=((pos-1)-((pos/3)+1))/2+1;
}else{
ans+=(pos+1)/2;
ans+=(pos-((pos+1)/3+1))/2+1;
}
if(pos%3==0 && pos/3%2==1) ans++;//特判
cout<<ans<<endl;
}
return 0;
}


错误次数:2次

原因:公式推演存在纰漏

原因:误以为是输出格式有问题,更改输出之后再次提交试验



I. Command Sequence

tag:

⇔模拟、⇔数据结构

题意:

有一串只包含 \(UDRL\) 的字符串,代表机器人的行动指令串。现在要求输出满足要求的字串数量。

要求:使得机器人进行若干行动后仍返回原地。

一共 \(T(1\leq T\leq 20)\) 组询问。每串指令长度为 \(L(2\leq T\leq 10^5)\) 。

思考过程:

(王晨杰)使用数组模拟机器人移动。使用二维map数组优化空间。

设置初始位置为 \((0,0)\) ,且令 \(mp[0][0]=1\) ,此后,每次移动,令目标位置的数组值加1,再判断此时目标位置数组是否大于1,大于1说明存在满足条件的字串,满足条件的子串数量即为 \(mp[x][y]-1\) ,将其加到答案中。

模拟如下:

【私人】2021.08.28 赛后小结——2021CCPC网络预选赛(第一场)_模拟

AC代码:

//team2699
#include<bits/stdc++.h>
using namespace std;
int q;
long long num;
char s;
void solve(){
cin>>n;
for(int i=0;i<n;i++){
cin>>s;
if(s=='D'){
mp[x][--y]+=1;
if(mp[x][y]>1) num+=(mp[x][y]-1);
}else if(s=='U'){
mp[x][++y]+=1;
if(mp[x][y]>1) num+=(mp[x][y]-1);
}else if(s=='R'){
mp[++x][y]+=1;
if(mp[x][y]>1) num+=(mp[x][y]-1);
}else if(s=='L'){
mp[--x][y]+=1;
if(mp[x][y]>1) num+=(mp[x][y]-1);
}
}
cout<<num<<endl;
}
int main(){
ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>q;
while(q--){
int num=0,x=0,y=0;
map<int, map<int, int > > mp;
mp[0][0]=1;
solve();
}
return 0;
}


错误次数:1次

原因:大数测试的时候少打一个零,没测到最大数据导致爆int了



F. Power Sum

tag:

⇔数论(规律题)

题意:

对于给定的 \(n(1\leq n\leq 10^6)\) ,找到任意的一个 \(k\),满足

  • \(1\leq k\leq n+2\)
  • \(n\) 可以由“ \(1\) 至 \(k^2\) 的所有平方数”经过相加减计算后得到。

一共 \(T(1\leq T\leq 100)\) 组询问。保证 \(\sum{n}\leq 3*10^7\) 。

输出第一行为 \(k\) 的值,第二行为详细操作:对于\(1\) 至 \(k^2\) 的所有平方数,若减去平方数,则输出 \(0\) ,若加上,则输出 \(1\) 。

例如:

  • \(4=-1^2-2^2+3^2\) 。\(k\) 即为3,详细操作为 \(001\) 。
  • \(4=1^2-2^2-3^2+4^2\) 。\(k\) 即为4,详细操作为 \(1001\) 。

思考过程:

刚拿到这道题的时候,略微推了一下,立即感觉到了这是一道数论题,突破点在于找到规律。

于是我开始打暴力,对于每个 \(n\) ,都输出它的最小的 \(k\) 值。结果发现根本没规律,于是全队陷入停滞,导致我一度想直接用打表做(从1打到650多)。

直到后来后来重新审视了一遍前10个数字的全部数据,才终于找到规律,如下:




n

1

1



2

0001



3

01001



4

1001



5

1

\(\widehat{1001}\)


6

0001

\(\widehat{1001}\)


7

01001

\(\widehat{1001}\)


8

1001

\(\widehat{1001}\)


9

1

\(\widetilde{1001}\)

\(\widetilde{1001}\)

10

0001

\(\widetilde{1001}\)

\(\widetilde{1001}\)

11

1001

\(\widetilde{1001}\)

\(\widetilde{1001}\)

每四个数字为一组,组成规律。

AC代码:

//A WIDA Project
#include<bits/stdc++.h>
int n,T,X;
string s;
int main(){
ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
cin>>T;
for(int i=1;i<=T;i++){
cin>>n;
s.clear();
X=n%4;
if(X==1) s+="1";
else if(X==2) s+="0001";
else if(X==3) s+="01001";
else if(X==0) s+="1001";
X=(n-1)/4;
for(int x=0;x<X;x++) s+="1001";
cout<<s.size()<<"\n"<<s<<"\n";
}
return 0;
}


错误次数:1次

原因:一开始找规律的时候是将输出的字符串反过来看的(因为这样规律更显眼一点),最后输出的时候就没有多考虑,直接写了个​​for​​循环取反,交了之后过了60分钟比赛结束了(土豆服务器,宕机4小时)才知道是超时,才意识到取反操作超时了,所以最后还是没能把这题A掉,有亿些可惜。



赛后小结

这场比赛我们团队发挥其实并不是很好。

在比赛前期,大家各自为营讨论思路,确定大致方向后确没有再做细致分析,没有统一团队思路,主副码手各自在思路存在分歧的情况下各自码题,导致比赛前半个小时团队较为混乱,第一题公式推演时出现重大纰漏,拖慢了全队进度。

比赛中期团队发挥尚可。

比赛进行到后期时,团队分工再次出现重大问题。我由于专心研究第三道(比赛顺序为第6题)数论题,在这期间未对团队策略进行明确评估,导致大家又出现了各自为营、各自开题的现象。以至于最后攻第三第四题都失败了,止步两题。作为队长,我在这段时间内存在较大失职,没能统筹各队员集中攻克一题,任大家各自发挥,双开两道题推进,导致比赛后三个小时团队效率极低。



补题计划与近期计划:

⇔数论、⇔规律题

一周五题+相应博客

Codeforces日常赛按照两场个人+一场团队的进度进行,尤其要注意团队赛的配合

【9月1日至9月4日】开始第二阶段集训

【九月每个周六周日(4、5、11、12、18、19、25、26)】ICPC各区域的预选赛

【时间未知】本次CCPC网络预选赛宣告作废,择日将进行重赛

【时间未知】CCCC大团队(10人)天梯赛