IO 2024 Round 3(团体赛)Unofficial Mirror

IO 2024 Round 3(团体赛)Unofficial Mirror

停课集训周三休息没啥事干继续打团战。

队员:
yangjinhua Hexiuqi 无名之雾

赛前写了个随机数选择使用 Hexiuqi 的号。

很早吃完饭从食堂往回走,期间 hxq 疯狂想要站在我和 yjh 中间于是便有了激烈的身体对抗。


赛时

开场开始随机开题。我觉得这个 A 的 \(n\le 70\) 难道不是宝宝题?然后就开始激烈的向 A 发起冲锋。冲了大概 \(20\) 分钟。yjh 和 hxq 就分别秒了 F/H 两个题。yjh 是 F 首杀。

然后 hxq 精确判断 B 是 签到,让我去写 B。然后我就被卡住了。我认为我需要更快的多源最短路算法!但我并不会更快的多源最短路算法。所以我不会这题。所以我觉得我应该需要一个更快的多源最短路算法···魔怔了 \(20\) 分钟我才发现这不是宝宝题。直接建一个虚点跑 dij 就行了。实现上甚至不需要把虚点建出来,所以写了一下就过了。

期间 hxq 说 L 是 FWT。然后 yjh 就光速过了。然后 hxq 在我写完 B 后跟我说 D 是宝宝题。直接写个搜把状态搜出来就过了。在我写 D 期间经历了:hxq 写 E 破防扔给 yjh。yjh 发现 G 数据有误疯狂 assert(0) 结果吃了 \(7\) 发罚时。

E/D 过了之后。我问了一下 hxq 感觉每题都有人开了,所以我去想 A 了。我坚定地认为这个 A 的 \(n\le 70\) 是宝宝题。然后我就开始带耳机听歌想题。

期间我隐约的听到了 yjh 在大喊 嘿嘿公鸡。然后我就看到 yjh 在对着自己的代码说话。内容大概是:

我让你说话了吗?你有什么资格说话?你这个都错你是废物吗?

他好像写了一个平衡树,我大受震撼啊。顺带一提的是,他在过了 C 之后不久。hxq 把 J 写完了过了。然后 G 数据修好也过了。现在我们来到了 \(9\) 题最后一名。大概是 G 数据干的。

我发现我似乎对于 A 会一个 \(35\) 的划分数 乘上 \(n^2\) 的做法。大概是 \(7\times 10^8\)。我觉得小常数卡卡就过。然后我就开写。期间 hxq 选择了 K 去做。yjh 选择了 I 去做。

因为一些搞笑原因以及我们队的罚时实在太高了。所以我直接把 A 题提交当厕所用,经常随便改一下就交。吃了 \(+16\) 的罚时。然后 yjh 看我罚时这么高了也把提交当厕所用,也吃了 \(+16\) 的罚时。期间他在调试他的主席树的时候继续:

我让你说话了吗?你有什么资格说话?你这个都错你是废物吗?

hxq 写了一发没过,看其他队都错这个点。所以以为数据有误所以很遗憾最后没过。痛失 AK。

\(11\) 题,rk1。比较搞笑的是因为我们罚时大于 \(24\) 小时了,所以溢出了。

没想到这个 A 就过了我一个?这么难的吗?


题解

A P14539 [IO 2024 #3] 固定船帆

感觉这个题本意是让你写一个 \(O(n^5)\) 或者 \(O(n^6)\) 的高复杂度 dp 但是我不会。考虑这个东西能不能搜。

首先把这个 w 当作分割符,把序列划分成若干连续段。手玩一下,发现很多情况下操作这个连续段的方式是很有规律的。

考虑分讨连续段中的 b 个数:

  • 当连续段中只有一个 b 的时候我们需要分别进行一次 rb
  • 当连续段中没有 b 的时候我们仅需要进行一次 r
  • 而当连续段中有很多 b 的时候我们进行完 rb 之后随意操作即可。

所以对于一个序列能否操作成功。我们只需要按照长度贪心匹配一下即可。

现在我们已经会 check 一个序列是否合法了,那么如何搜索呢?

我们发现实际上有很多序列其实是互相等价的。举个例子:

  • rbbbwrbbwrbwrbb
  • rbbwbbrwbbbrwbr

由于每个连续段是独立的,所以顺序是无用的。而考虑这两个序列的每个连续段中 b 的数量构成的集合都是 \(\{1,2,2,3\}\) 所以他们是等价的。

所以实际上我们搜索的状态并不会很多。状态大概是一个整数划分的东西。可能大概是 \(\dfrac{n}{2}\) 的划分数。

然后考虑怎么算答案。是一个多重集的排列数乘上一个方案数。

而方案数的算法也比较简单。随便插板法插一下就行了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    return s*w;
}
inline void out(int x){
    if(x==0){putchar('0');return;}
    int len=0,k1=x,c[10005];
    if(k1<0)k1=-k1,putchar('-');
    while(k1)c[len++]=k1%10+'0',k1/=10;
    while(len--)putchar(c[len]);
}
const int N=200,V=150,mod=1e9+7;
int inv[N],fac[N],vis[N],nxt[N],ans,flag[N],a[N];
int addmod(int x,int y){x+=y;if(x>=mod)x-=mod;return x;}
int mulmod(int x,int y){return x*y%mod;}
int submod(int x,int y){x-=y;if(x<0)x+=mod;return x;}
void init(int n){
    inv[0]=inv[1]=1;fac[0]=fac[1]=1;
    for(int i=2;i<=n;i++){
        inv[i]=mulmod((mod-mod/i),inv[mod%i]);
        fac[i]=mulmod(fac[i-1],i);
    }for(int i=1;i<=n;i++)inv[i]=mulmod(inv[i],inv[i-1]);
}
int c(int n,int m){
    if(n<m||m<0||n<0)return 0;
    return mulmod(mulmod(fac[n],inv[m]),inv[n-m]);
}string s;int n,k;
bool check(int x){
    memset(vis,0,sizeof vis);memset(flag,0,sizeof flag);
    for(int i=x;i>=1;i--){
        bool f=0;
        for(int j=1;j<=k;j++){
            if(!vis[j]&&s[j]=='r'){
                vis[j]=1;if(a[i]>1){
                    if(!nxt[j])return 0;
                    flag[nxt[j]]=i;vis[nxt[j]]=1;
                }f=1;break;
            }
        }if(!f)return 0;
    }int cnt=0;
    for(int i=k;i>=1;i--){
        if(!vis[i])cnt++;
        if(flag[i])cnt-=a[flag[i]]-2;
        if(cnt<0)return 0;
    }return 1;
}
void dfs(int x,int lst,int c1,int c2){
	if(c2>n)return ;if(!check(x))return ;
    int cnt=c(n-c2+c1+x,c1+x);cnt=mulmod(cnt,fac[x]);
    for(int i=1;i<=x;i++){
        int fail=i;
        while(fail<x&&a[fail]==a[fail+1])fail++;
        cnt=mulmod(cnt,inv[fail-i+1]);i=fail;
    }ans=addmod(ans,cnt);if(x==max(n,k))return ;
	for (int i=lst;i<=max(n,k);i++){
		a[x+1]=i;dfs(x+1,i,c1+(i*2-1),c2+(i<3?1:i*2-3)+(x!=0));
	}return ;
}
signed main(){
    init(V);n=read(),k=read();cin>>s;s=' '+s;
	for(int i=1;i<=k;++i){
		if(s[i]=='r'){
			for(int j=i;j<=k;++j){
				if(!vis[j]&&s[j]=='b'){nxt[i]=j;vis[j]=1;break;}
			}
		}
	}
	dfs(0,1,0,0);cout<<ans;
    return 0;
}

B P14540 [IO 2024 #3] 岛屿追逐

赛时对着这个魔怔了半天差点让我身败名裂了。

以每个点为起点跑最短路显然是不聪明且难以优化的。由于终点是任选的,所以考虑建反图。并且开一个虚点连接每一个 \(i\) 边权为 \(a_i\) 然后反图的边权为原图的 \(2\) 倍。这样虚点到每个点的最短路就是答案。跑 dij 即可。

具体实现上不需要把虚点显式建出来,因为虚点的第一次扩展会把所有点都加进来,所以手动往 pq 里加一遍就行。

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    return s*w;
}
inline void out(int x){
    if(x==0){putchar('0');return;}
    int len=0,k1=x,c[10005];
    if(k1<0)k1=-k1,putchar('-');
    while(k1)c[len++]=k1%10+'0',k1/=10;
    while(len--)putchar(c[len]);
}
const int N=2e5+5,INF=2e9+9;int n,m,s;
vector<pair<int,int>>edge[N];int dist[N],vis[N],a[N];
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
void dij(){
    while(!q.empty()){
        auto [w,id]=q.top();q.pop();
        if(vis[id])continue;vis[id]=1;
        for(auto [i,v]:edge[id]){
            if(dist[i]>dist[id]+v){
                dist[i]=dist[id]+v;
                q.emplace(dist[i],i);
            }
        }
    }
}
signed main(){
    int n=read(),m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),w=read();
        edge[u].push_back({v,2*w});
        edge[v].push_back({u,2*w});
    }for(int i=1;i<=n;i++)dist[i]=INF;
    for(int i=1;i<=n;i++){
        dist[i]=a[i];
        q.push({dist[i],i});
    }
    // for(int i=1;i<=n;i++)cout<<dist[i]<<" ";puts("");
    dij();
    for(int i=1;i<=n;i++)cout<<dist[i]<<" ";
    return 0;
}

C P14541 [IO 2024 #3] 嘿嘿公鸡与石头

没看题啊。场上 yjh 一边大叫一边就写完了。先搁着。

D P14542 [IO 2024 #3] 又一场游戏

这个是真宝宝题。hxq 说把状态都搜出来就行了。但实际上并不需要这么麻烦。

我们有人连两个的时候就堵,没人就随便下。这个正确性是显然的,随便搜一下结束了。

要注意的是这个神人交互库不会自己停。所以你还需要判一下棋盘有没有被填满手动结束。赛时因为这个吃了好几发罚时。

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    return s*w;
}
inline void out(int x){
    if(x==0){putchar('0');return;}
    int len=0,k1=x,c[10005];
    if(k1<0)k1=-k1,putchar('-');
    while(k1)c[len++]=k1%10+'0',k1/=10;
    while(len--)putchar(c[len]);
}
char g[5][5];
pair<int,int>f(char p){
    for(int i=1;i<=3;i++){
        int c1=(g[i][1]==p),c2=(g[i][2]==p),c3=(g[i][3]==p);
        if(c1+c2+c3==2){
            if(g[i][1]=='.')return{i,1};
            if(g[i][2]=='.')return{i,2};
            if(g[i][3]=='.')return{i,3};
        }c1=(g[1][i]==p),c2=(g[2][i]==p),c3=(g[3][i]==p);
        if(c1+c2+c3==2){
            if(g[1][i]=='.')return{1,i};
            if(g[2][i]=='.')return{2,i};
            if(g[3][i]=='.')return{3,i};
        }
    }int d1=(g[1][1]==p),d2=(g[2][2]==p),d3=(g[3][3]==p);
    if(d1+d2+d3==2){
        if(g[1][1]=='.')return{1,1};
        if(g[2][2]=='.')return{2,2};
        if(g[3][3]=='.')return{3,3};
    }d1=(g[1][3]==p),d2=(g[2][2]==p),d3=(g[3][1]==p);
    if(d1+d2+d3==2){
        if(g[1][3]=='.')return{1,3};
        if(g[2][2]=='.')return{2,2};
        if(g[3][1]=='.')return{3,1};
    }return{-1,-1};
}
pair<int,int> p(){
    if(g[2][2]=='.') return {2,2};
    vector<pair<int,int>>corn={{1,1},{1,3},{3,1},{3,3}};
    for(auto c:corn)if(g[c.first][c.second]=='.')return c;
    vector<pair<int,int>>s={{1,2},{2,1},{2,3},{3,2}};
    for(auto c:s)if(g[c.first][c.second]=='.')return c;
    return {-1,-1};
}string line;
signed main(){
    for(int i=1;i<=3;i++)for(int j=1;j<=3;j++)g[i][j]='.';
    while(1){bool flag=0;
        for(int i=1;i<=3;i++){
            for(int j=1;j<=3;j++){
                if(g[i][j]=='.')flag=1;
            }
        }if(!flag)return 0;
        string t;cin>>t;
        if(t=="OK")continue;
        if(t=="X"){
            int r,c;cin>>r>>c;g[r][c]='X';
            pair<int,int>mv={-1,-1};
            auto bh=f('#');if(bh.first!=-1)mv=bh;
            else{
                auto bx=f('X');if(bx.first!=-1)mv=bx;
                else mv=p();
            }if(mv.first==-1)break;
            cout<<"0 "<<mv.first<<" "<<mv.second<<endl;
            g[mv.first][mv.second]='O';
        }else if(t=="#"){
            int r,c;cin>>r>>c;
            g[r][c]='#';
        }else continue;
    }
    return 0;
}
posted @ 2025-11-20 22:53  无名之雾  阅读(25)  评论(0)    收藏  举报