2025ccpc全国邀请赛(郑州)游记 + 前7题题解
(中间是我

赛前
6.2比赛,5.31前往郑州,正好赶上从游族实习离职。
早上七点多,背着大包小包前往上海南站,坐上了离开上海的高铁。
五个小时后,抵达郑州。
地铁非常方便,很快到学校附近,只是不知道地铁站到酒店居然有2km,推着一个大行李箱,和一个大羽毛球包,走了四十分钟才到酒店,折磨完了。
四点多到酒店,睡到了八点多,成功错过当晚abc。
十点多两个队友从保定坐高铁赶到。我跟他们说,楼下买一大桶水,这两天喝。然后他们买了三大桶,到最后还剩一桶5升的农夫山泉没喝完,拎到赛场又拎到了保定。
正好还能赶得上十点半的cf,成功上分。
十二点半cf结束后,都不困,遂继续补题,开始补之前vp的题目。
三点钟看了会欧冠决赛,这么多年巴黎终于是冠军了。
时间已经到了凌晨五点多,又一起商量了一下校集训队的规划,心情比较激动再加上睡了一下午,根本不困
于是6点多去楼下吃了豆腐脑+油条,上次吃甜豆腐脑好像还是很小的时候
将近七点才回酒店睡下,本来还想九点多去报道,一觉睡到了中午
两点多,罗老师到酒店后,才一起去赛场报到(今年发的衣服是真丑
下午是热身赛,出现了很多问题,卡评测,本地卡顿,等等一堆问题,但是第二天正式赛基本解决好了
当天晚上和罗老师聊了一会校集训队的规划,队友vp了会今年东北赛的题(不出意外的出意外了
而我呢
不得不准备6.3外教课考试的演讲稿
第二天早上不出意外没起来,还是罗老师打电话叫起来+买饭送到房间的
推着箱子到赛场,好像找不到比我行李更多的了
进入赛场,又坐到了xcpc的赛场中
赛时
前期推进还算顺利,大方向没问题,小错误一堆,每个题至少1个罚时,包括D签到题数开小了,E没开ll各wa了一发
赛时第一视角:
开局发现D是签到,于是wa1发后过D
队友发现J是签到,队友wa1发后过J
M好像比较简单,敲了个并查集上去很快过掉
看了会H题,发现好像是个诈骗题,直接输出r-l+1过掉
队友说会F了,写了个神秘二分上去,wa两发,至今不知道是怎么二分的(赛后高铁上又提出神秘分层图做法
看F,发现多源多终点01BFS即可,小细节tle一发后过掉
开G题构造题,发现奇数情况后,交给队友写,我去看E
队友思考半小时后成功得出一眼假的思路并wa一发,被我发现后狠狠压力
想出通解后让队友上机敲出代码,过掉G
开始看E题,感觉非常神秘,一开始有两个方向的思路,把组分出来,和不分组直接算
看榜过了一车人,感觉应该不是难题,但想半天想不出来
猜了一发根据奇偶位置分组,并用字典树维护
第一发wa了 彻底绝望,苦思冥想是哪里错了 此时队友提出是不是没开ll
果然define int ll后一发过掉
此时已经封榜,位于银牌区倒数
下一个BCK必须开一题,才能到银牌,最后B题三维优化概率DP,C题珂朵莉树维护区间,K题神秘卷积优化
实在是拼尽全力无法战胜
最终7题841罚时,遗憾铜首
赛后30块钱的比赛饭卡里还有不少钱,买了一堆吃的和饮料带了回去
罗老师还买了一堆咸鸭蛋
最后
深夜写下这篇流水账游记,这可能是大三老登最后一次比赛了,下半年网络赛想打出名额,靠一个人肯定是不可能的
只能期待学弟们,能提升实力到能和我一起多线程开题的水平,以及自己的实力能有提升
希望以后还能有机会参赛吧
真的还想打比赛
题解:
Problem D. 2025
签到题,第一发因为只循环到了500,wa了
点击查看代码
#include<iostream>
using namespace std;
void solve(){
int n;
cin>>n;
int t=n;
int val=0;
while(t){
val+=t%10;
t/=10;
}
bool f1=0,f2=0;
for(int i=1;i<=1000;i++){
if(i*i==n) f1=1;
if(i*i==val) f2=1;
}
if(f1 && f2){
cout<<"Yes";
}else{
cout<<"No";
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
/**********************************************************************
Problem: 1009
User: D1003
Language: C++
Result: AC
Time:2 ms
Memory:2304 kb
**********************************************************************/
Problem J. Ring Trick
签到题,没看题,队友过的
点击查看代码
#include <bits/stdc++.h>
int main()
{
std::ios::sync_with_stdio(false),std::cin.tie(nullptr);
auto s = std::string{};
auto constexpr hole = std::array {
1,2,0,1,0,0,0,0,0,0,0,0,0,
0,1,1,1,1,0,0,0,0,0,0,0,0
};
std::cin >> s;
auto n = int(s.size());
auto ans = 0;
for(auto k = 0; k != 26; ++k) {
auto cnt = 0;
for(auto i = 0; i != n; ++i) {
cnt += hole[(s[i] - 'A' + k) % 26];
}
ans = std::max(ans,cnt);
}
std::cout << ans << '\n';
}
/**********************************************************************
Problem: 1015
User: D1003
Language: C++
Result: AC
Time:33 ms
Memory:3876 kb
**********************************************************************/
Problem M. 川陀航空学院
首先,对于每一个节点个数为 t 的连通块,把边的数量删到 t-1
然后,再把 x 个不用的联通块用 x-1 条边连起来即可,全程可以用并查集维护
点击查看代码
#include<iostream>
#include<vector>
#include<algorithm>
#include<numeric>
#include<map>
using namespace std;
int cnt;
class dsu{
public:
vector<int> fa,sz,edge;
int setCount;
int n;
dsu(){};
dsu(int n){
fa.assign(n+1,0);
sz.assign(n+1,1);
edge.assign(n+1,0);
this->n=n;
setCount=n;
iota(fa.begin(),fa.end(),0);
}
int find(int x){
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
void unite(int x,int y){
x=find(x),y=find(y);
if(x==y){
cnt++;
return;
}
if(sz[x]<=sz[y]) swap(x,y);
fa[y]=fa[x];
sz[x]+=sz[y];
--setCount;
edge[x]++;
edge[x]+=edge[y];
}
};
void solve(){
int n,m;
cin>>n>>m;
dsu ds(n);
// int cnt=0;
while(m--){
int u,v;
cin>>u>>v;
ds.unite(u,v);
}
for(int i=1;i<=n;i++){
if(ds.find(i)!=i) continue;
cnt+=ds.edge[i]-(ds.sz[i]-1);
}
cnt+=ds.setCount-1;
cout<<cnt;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
/**********************************************************************
Problem: 1018
User: D1003
Language: C++
Result: AC
Time:188 ms
Memory:14028 kb
**********************************************************************/
Problem H. 树论函数
打表发现,n 和 n+1 联通,又因为范围是无穷,且赛时过了一车人,guess了一发都联通,ac
具体的证明可以看gym上的官方题解,写的很清楚,大概就是 n 和 n+1 一定和更大的一个点 x 联通
点击查看代码
#include<iostream>
using namespace std;
void solve(){
int s,l,r;
cin>>s>>l>>r;
cout<<r-l+1<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
/**********************************************************************
Problem: 1013
User: D1003
Language: C++
Result: AC
Time:313 ms
Memory:2304 kb
**********************************************************************/
Problem F. 幻形之路
先特判一下能不能直接走到,如果可以直接输出0即可
把 (1,1)能走到的所有障碍物,设置成源点,放进队列,把(n,m)能走到的所有非障碍物,设置成终点。
因为边权是1,所以BFS即可
点击查看代码
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<vector>
#define endl '\n';
using namespace std;
using pii=pair<int,int>;
const int N=1010;
const int inf=1e9;
char g[N][N];
int st[N][N];
int dist[N][N];
int n,m;
queue<pii> q;
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};
void bfs1(int x,int y,int mk){
st[x][y]=1;
for(int i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a>=1 && a<=n && b>=1 && b<=m && !st[a][b]){
if(g[a][b]=='.') bfs1(a,b,mk);
else if(mk==0){
q.push({a,b});
dist[a][b]=1;
st[a][b]=1;
}
}
}
}
void solve(){
cin>>n>>m;
while(q.size()) q.pop();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>g[i][j];
st[i][j]=0;
dist[i][j]=inf;
}
}
bfs1(1,1,0);
if(st[n][m]){
cout<<0<<endl;
return;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
st[i][j]=0;
}
}
bfs1(n,m,1);
int ans=n+m-2;
while(q.size()){
auto [x,y]=q.front();
q.pop();
// cout<<"i: "<<x<<" j: "<<y<<" dist: "<<dist[x][y]<<endl;
for(int i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a>=1 && a<=n && b>=1 && b<=m){
if(st[a][b]==0 && dist[x][y]+1<dist[a][b]){
dist[a][b]=dist[x][y]+1;
q.push({a,b});
}
else if(st[a][b]==1 && dist[x][y]<dist[a][b]){
dist[a][b]=dist[x][y];
ans=min(ans,dist[a][b]);
}
}
}
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
/**********************************************************************
Problem: 1011
User: D1003
Language: C++
Result: AC
Time:53 ms
Memory:104900 kb
**********************************************************************/
Problem G. 直径与最大独立集
特判一下2和4
然后奇数偶数分别如下构造

点击查看代码
#include <bits/stdc++.h>
void solve()
{
int n;
std::cin >> n;
if(n == 2) {
std::cout << 1 << ' ' << 2 << '\n';
return;
}
if(n == 4) {
std::cout << -1 << '\n';
return;
}
auto d = (n / 2) + 1; // zhi jing
auto now = (d / 2) + 1; // xian zai you de
auto have = n - d - 1; // bu de dian
auto even = d - now;
auto odd = have - even;
auto tot = d + 2;
for(auto i = 1; i < tot - 1; i += 1) {
std::cout << i << ' ' << i + 1 << '\n';
}
auto it = 2;
while(have) {
std::cout << it++ << ' ' << tot++ << '\n';
--have;
}
// std::cout << std::format("even = {},odd = {}\n",de,doo);
}
int main()
{
std::ios::sync_with_stdio(false),std::cin.tie(nullptr);
int t;
std::cin >> t;
while(t--) {
solve();
}
}
/**********************************************************************
Problem: 1012
User: D1003
Language: C++
Result: AC
Time:8 ms
Memory:2304 kb
**********************************************************************/
Problem E. 双生魔咒
结论是排序后根据奇偶位置分组
说下赛时感性的推测
对每个字符串 i ,肯定要尽量把前缀最匹配的字符串 j 放到另一个组
而按排序奇偶位置分组,刚好满足这个要求
同时赛时过了一车人,感觉不是难题
分组后计算答案时,把其中一组放进字典树中即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int tr[N][26];
int idx;
int cnt[N*26];
int ans;
void insert(string &s){
int now=0;
for(int i=0;i<s.size();i++){
int ch=s[i]-'a';
if(tr[now][ch]==0){
tr[now][ch]=++idx;
}
now=tr[now][ch];
cnt[now]++;
}
}
void find(string &s){
int now=0;
for(int i=0;i<s.size();i++){
int ch=s[i]-'a';
if(tr[now][ch]==0){
return;
}
now=tr[now][ch];
ans+=cnt[now];
}
}
void solve(){
int n;
cin>>n;
vector<string> a(2*n+1);
for(int i=1;i<=2*n;i++){
cin>>a[i];
}
sort(a.begin()+1,a.end());
for(int i=1;i<=2*n;i++){
if(i&1) insert(a[i]);
}
for(int i=1;i<=2*n;i++){
if(!(i&1)) find(a[i]);
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
/**********************************************************************
Problem: 1010
User: D1003
Language: C++
Result: AC
Time:26 ms
Memory:89820 kb
**********************************************************************/

浙公网安备 33010602011771号