当前位置: 首页 > news >正文

GJOI 9.11/9.13 题解

因为这两次测试的后两题都不太可补,于是放在一起。不过前面的题目质量都挺高的。

1.排序

题意

在这里插入图片描述

思路

我做这种计数 dp 依然垃圾。因为最后那一步 swap 我直接迷茫了。

先看到这个 partition 函数,对于 al∼ra_{l\sim r}alr,以 ara_rar 为基准,设对这个区间排序之后 ara_rar 所在位置为 xxx

  • 将小于 ara_rar 的数顺序不变地放到 l∼x−1l\sim x-1lx1
  • 将大于 ara_rar 的数顺序不变地放到 x∼r−1x\sim r-1xr1
  • 将处理完后,在 xxx 上的数和 ara_rar 交换,使 ara_rar 在正确的位置上;
  • Qsort 中分治,处理 [l,x)[l,x)[l,x)(x,r](x,r](x,r]

虽然说 partition 函数最后一步 swap 会打乱原来的顺序,但是对于所有排列而言,大于 ara_rar 的数所有形态的排列顺序都会等概率出现,因而影响不大。

fi,kf_{i,k}fi,k 表示对 iii 个数的排列递归至少 kkk 层(注意和询问所给的 kkk 含义不同,因为 Qsort 中只有 k>1k>1k>1 时才能继续递归,实际递归层数为 k−1k-1k1),能够变为有序的排列数。

我们发现决定排序后形态的是最后一个数,考虑枚举 1∼i1\sim i1i 中最后一个数(排名)为 lll,因此小于 llll−1l-1l1 个数还可以递归 k−1k-1k1 层,大于 llli−li-lil 个数还可以递归 k−1k-1k1 层,即 fi−1,k−1×fi−l,k−1f_{i-1,k-1}\times f_{i-l,k-1}fi1,k1×fil,k1

我们想要再递归 1111∼i1\sim i1i 就被排序好了,因此当前小于 llll−1l-1l1 个数、大于 llli−li-lil 的数要有序排好。但是根据 partition 的功能,不一定要小于的、或大于的全部挨在一起,它们之间可以相互插入,只要相对有序即可。这样打乱插入的方案数就是在前面 i−1i-1i1 个数选择 i−li-lil 个位置写上大于 lll 的数,即 (i−1i−l)\binom{i-1}{i-l}(ili1)(i−1l−1)\binom{i-1}{l-1}(l1i1)
fi,k←fl−1,k−1×fi−l,k−1×(i−1i−l)f_{i,k}\leftarrow f_{l-1,k-1}\times f_{i-l,k-1}\times \binom{i-1}{i-l}fi,kfl1,k1×fil,k1×(ili1)

预处理 O(n2k)=O(n3)O(n^2k)=O(n^3)O(n2k)=O(n3),根据上文 O(1)O(1)O(1) 查询答案为 fn,k−1f_{n,k-1}fn,k1

记得勤取模。然后模拟赛时一定要勤思考,不要想一会没想到就问别人,不会就是不会,赛后补就好了。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=302;
ll Q,mod;
ll f[N][N];
ll C[N][N];
void init()
{for(int i=1;i<N;i++)C[i][0]=C[i][i]=1;for(int i=1;i<N;i++){for(int j=1;j<i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;}
}
int main()
{
//	freopen("sort.in","r",stdin);
//	freopen("sort.out","w",stdout);scanf("%lld%lld",&Q,&mod);init();for(int i=0;i<N;i++){f[0][i]=f[1][i]=1;}for(int i=2;i<N;i++){for(int k=1;k<N;k++){f[i][0]=1;for(int l=1;l<=i;l++){f[i][k]=(f[i][k]+f[l-1][k-1]*f[i-l][k-1]%mod*C[i-1][i-l]%mod)%mod;}}}while(Q--){ll n,k;scanf("%lld%lld",&n,&k);printf("%lld\n",f[n][k-1]);}return 0;
}

2.CF1975D Paint the tree

题意

在这里插入图片描述
ttt 组测试数据,1≤t≤51\le t\le 51t51≤n≤2×1051\le n\le 2\times 10^51n2×105

思路

gzw 时期的题目,当时可做不出来,现在感觉不难。

一个显然的贪心:AAABBB 相遇之后,才能产生贡献,即 BBBAAA 一起走(a,ba,ba,b 能在一个点相遇)或者 BBB 跟在 AAA 的尾巴(a,ba,ba,b 不能在一个点相遇)。在新的 b′b'b 重构整棵树,遍历 n−1n-1n1 边 ,走下去再走回来 b′b'b(这样会遍历每条边 222 次),最后遍历 b′b'b 为根的最长链时,就不用再回到 b′b'b 了,于是减去 DpstDpstDpst

发现如果 Disa,bDis_{a,b}Disa,b 为偶数,两点可以在一个点相遇,这很好搞,直接在 a→ba\to bab 路径上,两点都跳 Disa,b2\frac{Dis_{a,b}}{2}2Disa,b 步即可。答案为 Disa,b2+2(n−1)−Dpst\frac{Dis_{a,b}}{2}+2(n-1)-Dpst2Disa,b+2(n1)Dpst

如果为奇数,两点跳 ⌊Disa,b2⌋\left\lfloor \frac{Dis_{a,b}}{2} \right\rfloor2Disa,b 步后还差一条边相遇。如果从现在的 b′b'b 开始重构,BBB 就跑到 AAA 前面了,于是我们让 BBB 多跳一步到 a′a'a,此时 AAA 也会随便跳到 a′a'a 周围随便一点 a′′a''a′′,在 a′a'a 重构整棵树然后 BBB 沿着 AAA 的轨迹跑即可,只要 a′′a''a′′ 不在 a′a'a 为根的最长链,就是最优方案。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=2e5+9;
ll Q,n,a,b;
struct edge
{ll to,next;
}e[N<<1];
ll idx,head[N];
void addedge(ll u,ll v)
{idx++;e[idx].to=v;e[idx].next=head[u];head[u]=idx;
}
ll Ceil(ll fz,ll fm)
{return (fz+fm-1)/fm;
}
ll Dep[N],dis[N],Fat[N];
void dfs2(ll u,ll fa)
{Dep[u]=Dep[fa]+1;Fat[u]=fa;for(int i=head[u];i;i=e[i].next){ll v=e[i].to;if(v==fa)continue;dfs2(v,u);}
}
void clean()
{idx=0;memset(e,0,sizeof(e));memset(head,0,sizeof(head));memset(f,0,sizeof(0));memset(fat,0,sizeof(fat));
}
int main()
{freopen("col.in","r",stdin);freopen("col.out","w",stdout);scanf("%lld",&Q);while(Q--){scanf("%lld%lld%lld",&n,&a,&b);clean();for(int i=1;i<n;i++){ll u,v;scanf("%lld%lld",&u,&v);addedge(u,v);addedge(v,u);}dfs2(a,0);ll cur=b,tot=0;for(int i=1;i<=n;i++)dis[i]=Dep[i]-1;while(dis[cur]>Ceil(dis[b],2)){cur=Fat[cur];tot++;}if(dis[b]&1){tot++,cur=Fat[cur];}dfs2(cur,0);ll Dpst=0;for(int i=1;i<=n;i++)Dpst=max(Dpst,Dep[i]-1);printf("%lld\n",tot+2*(n-1)-Dpst);}return 0;
}

upd:为什么跑“中点”相遇就是正确的?假如存在一个最优重构点 ccc,依然想 A,BA,BA,B 都走到 cccAAA 需要先走到,实则这个点不管在树上什么位置,a→ca\to cacb→cb\to cbc 的过程两个人轨迹相并必然覆盖了整个 a→ba\to bab 的路径。
在这里插入图片描述

可以预见的,可能在 ccc 处重构的最长链更长,但是 AAA 先到 ccc 之际,和 BBB 拉开了一段距离要弥补回来,这就用 DpstcDpst_cDpstcDpstmidDpst_{mid}Dpstmid 之差不回来。因此在中点 midmidmid 或者中间边相遇必然不劣。

后面 222 题感觉实在不是我能补的啊,但是同机房大佬 Garbage_fish 和 Fireworks_Rise 。欢迎右转前往他的超详细博客和他的超详细博客。

接下来是 GJOI 9.13,这后面同样有很难补的两题。

3.洛谷 P11662 JOI 2025 Final 方格染色 / Grid Coloring

题意

在这里插入图片描述
2≤N≤2×1052\le N\le 2\times 10^52N2×105Ai,Bi∈[1,109]A_i,B_i\in[1,10^9]Ai,Bi[1,109],保证 A1=B1A_1=B_1A1=B1

思路

显然 (1,1)(1,1)(1,1) 不会参与任何格子的最大值贡献。记 ai=max⁡i=2nAi,bi=max⁡i=2nBi\displaystyle a_i=\max_{i=2}^n A_i,b_i=\max_{i=2}^n B_iai=i=2maxnAi,bi=i=2maxnBi,那么 (i,j)(i,j)(i,j) 格子上的数为:
max⁡(ai,bj)\max(a_i,b_j)max(ai,bj)

分别考虑有多少格子的 max⁡(ai,bj)=ai\max(a_i,b_j)=a_imax(ai,bj)=ai 以及 bjb_jbj。显然 a,ba,ba,b 数组都是单调不降的,因此可以二分有多少 bj≤aib_j\le a_ibjai,那么 (i,2∼j)(i,2\sim j)(i,2j) 都要填 aia_iai。同样二分多少 ai<bja_i<b_jai<bj,那么 (2∼i,j)(2\sim i,j)(2i,j) 都要填 bjb_jbj。(这里不用 ≤\le 是因为在算 bj≤aib_j\le a_ibjai 时已经算过等于的情况了)

二分 lower_bound 平替即可,记数懒得离散化就 map

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2e5+9;
ll n,x;
ll a[N],b[N];
map<ll,ll>cnt;
ll tot,ans;
void merge(ll x)
{if(cnt[x]>tot)tot=cnt[x],ans=x;else if(cnt[x]==tot&&x>ans)ans=x;
}
int main()
{freopen("grid.in","r",stdin);freopen("grid.out","w",stdout);scanf("%lld",&n);scanf("%lld",&x);cnt[x]++;merge(x);for(int i=2;i<=n;i++){scanf("%lld",&x);cnt[x]++;merge(x);a[i]=max(a[i-1],x);}scanf("%lld",&x);for(int i=2;i<=n;i++){scanf("%lld",&x);cnt[x]++;merge(x);b[i]=max(b[i-1],x);}
//	for(int i=1;i<=5;i++)
//	cout<<cnt[i]<<" ";
//	cout<<endl;
//	cout<<ans1<<endl;for(int i=2;i<=n;i++){ll pos=upper_bound(b+2,b+n+1,a[i])-b-2;cnt[a[i]]+=pos;merge(a[i]);}for(int i=2;i<=n;i++){ll pos=lower_bound(a+2,a+n+1,b[i])-a-2;cnt[b[i]]+=pos;merge(b[i]);}printf("%lld %lld",ans,tot);return 0;
}

4.洛谷 P12576 UOI 2021 数字图

题意

在这里插入图片描述
1≤2.5×105,1≤m≤5×1051\le 2.5\times 10^5,1\le m\le 5\times 10^512.5×105,1m5×105ai∈[1,109]a_i\in[1,10^9]ai[1,109]

思路

本篇博客实现参考这篇博客。

看到博弈论感觉来到盲区了。

我们发现 sub4 只有 1,21,21,2。那么先手会尽全力走到 222,后手会尽全力走到 111;一旦先手走到 111,后手立即结束游戏;一旦后手走到 222,先手立即结束游戏。

那么 a1=2a_1=2a1=2 先手必赢。我们考虑 a1=1a_1=1a1=1 的情况。在 111,先手为了不输,肯定不会走到相邻的 111,所以会走到 ax=2a_{x}=2ax=21,x1,x1,x 有边相连);在 xxx,后手为了不输,肯定不会走到相邻的 222,所以会走到 ay=1a_y=1ay=1x,yx,yx,y 有边相连);……如此循环往复。

那么聪明的两人必然不会走 au=ava_u=a_vau=av 的边 u→vu\to vuv。建出一个没有两点点权相同的边的图,从 111 开始走,如果使得后手走到某个点没有出度先手必胜,否则后手必胜。

依据这个博弈模拟这个过程。


文章转载自:

http://Tm6i87Nl.wbxtx.cn
http://QDlO72oL.wbxtx.cn
http://utXK2gSy.wbxtx.cn
http://E2MVFHdb.wbxtx.cn
http://ltXPRCTt.wbxtx.cn
http://r2yBr61n.wbxtx.cn
http://k3uflflB.wbxtx.cn
http://yRyTfpRp.wbxtx.cn
http://K5EFhaDM.wbxtx.cn
http://fgTU8Td5.wbxtx.cn
http://VmHRtVIX.wbxtx.cn
http://UgzU2x91.wbxtx.cn
http://lG3tbJsJ.wbxtx.cn
http://vWg9a1dh.wbxtx.cn
http://6AHGJk0L.wbxtx.cn
http://b3qZppku.wbxtx.cn
http://TEZRnlZK.wbxtx.cn
http://rHI89NWR.wbxtx.cn
http://YQonOREz.wbxtx.cn
http://fIdM9TqG.wbxtx.cn
http://egVn2MuZ.wbxtx.cn
http://gXTULopF.wbxtx.cn
http://yDz7dMNT.wbxtx.cn
http://VQuvSWo0.wbxtx.cn
http://mloQM0GT.wbxtx.cn
http://vPuJE5kc.wbxtx.cn
http://E6DNigee.wbxtx.cn
http://9rjB40Jq.wbxtx.cn
http://7MCg5CxP.wbxtx.cn
http://mMOaUBzO.wbxtx.cn
http://www.dtcms.com/a/388281.html

相关文章:

  • 基于Spark的用户实时分析
  • 什么是 Conda 环境?
  • RK3506开发板QT Creator开发手册,交叉编译工具链与QT应用示例,入门必备
  • 颠覆3D生成,李飞飞团队新研究实现3D场景「无限探索」,AI构建世界模型能力跨越式进化
  • 3D 大模型生成虚拟世界
  • AI技术全景图:从大模型到3D生成,探索人工智能的无限可能
  • 一天认识一种模型方法--3D人体建模 SMPL
  • World Labs 的核心技术介绍:生成持久、可导航的 3D 世界
  • websocket如何推送最新日志
  • 使用Docker部署bewCloud轻量级Web云存储服务
  • web Service介绍
  • Web 架构中的共享存储:NFS 部署与用户压缩
  • RuoYi整合ZLM4j+WVP
  • @CrossOrigin的作用
  • Tree-shaking【前端优化】
  • Scikit-learn Python机器学习 - 分类算法 - 随机森林
  • 深入浅出Java中的Happens-Before原则!
  • centos7更换yum源
  • [特殊字符] 认识用户手册用户手册(也称用户指南、产品手册)是通过对产品功能的清
  • Codex 在 VS Code/Cursor 的插件基础配置
  • 前端Web案例-登录退出
  • Redis学习------------缓存优化
  • openfeigin 跨服务调用流程 源码阅读
  • 运动手环心率监测:原理、可靠性与市场顶尖之选全解析​​
  • 端到端智驾测试技术论文阅读
  • Frank-Wolfe算法:深入解析与前沿应用
  • GPT-5-Codex CLI保姆级教程:获取API Key配置与openai codex安装详解
  • 代码优化测试
  • 深度学习基础:PyTorch张量创建与操作详解
  • 7 大文献综述生成工具 2025 实测推荐