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的时候我们需要分别进行一次r和b。 - 当连续段中没有
b的时候我们仅需要进行一次r。 - 而当连续段中有很多
b的时候我们进行完rb之后随意操作即可。
所以对于一个序列能否操作成功。我们只需要按照长度贪心匹配一下即可。
现在我们已经会 check 一个序列是否合法了,那么如何搜索呢?
我们发现实际上有很多序列其实是互相等价的。举个例子:
rbbbwrbbwrbwrbbrbbwbbrwbbbrwbr
由于每个连续段是独立的,所以顺序是无用的。而考虑这两个序列的每个连续段中 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;
}

浙公网安备 33010602011771号