Atcoder Regular Contest 165

B. Sliding Window Sort 2

被题目名里的滑动窗口误导了,于是卡 B 40min /fn

Description

给定长度为 \(n\) 的排列 \(P\) 和一个整数 \(K\)。一次操作定义为选择一个长度为 \(K\) 的区间,对原排列的这段区间升序排序,其余位置不变。

你要执行操作恰好一次,求能得到的字典序最大的排列。

\(1\le K \le N\le 2\times 10^5\)

Solution 1

题解做法。

观察到由于操作是升序排列,操作之后不会使排列的字典序变得比原来更大。那么如果存在某种操作方式使得这个区间不变,这样做一定是最优的。这种情况等价于找一个长度为 \(K\) 的单调递增区间,而这是容易判断的。

考虑不存在上述区间的情况,即无论如何操作都会使排列的字典序变小。我们显然更希望操作后值被改变的第一个位置尽可能靠右。设这个位置的下标为 \(x\)

可以发现,当选择区间 \([n-K+1,K]\) 时,\(x\) 可以取得下界 \(n-K+1\)。也就是说,如果一个操作改变了 \(n-K+1\) 左侧的位置,这个操作不如最后一个区间优,它一定不是答案。但直接操作最后一个区间并不一定是最优的。如果最后一个区间后面的部分有一些很小的数,把操作区间左移避开它们或许更优。

将操作区间左移至 \([L,R]\),要使答案不变劣,应当保证 \(n-K+1\) 前面的部分都不变,即 \([L,n-K]\) 的值单调递增且均小于后面。在满足条件的情况下,显然 \(L\) 变小答案不会变劣,因此我们只需找到最小满足条件的 \(L\)

对于“全部小于后面”的条件,因为单调递增,只需满足 \(P_{n-K}\) 小于后面的最小值,可以得出 \(L\) 的上界。而通过“单调递增”的条件可以得出 \(L\) 的下界,我们在 \(L\) 存在(上界不小于下界)的情况下取最小的 \(L\),不存在就取 \(n-K+1\) 作为区间左端点进行操作即可。

Solution 2

这人被题目名误导弄出来的赛时做法,给大家看个乐子。

我们希望第一个被改变的位置尽可能靠后。因此,类似于滑动窗口,从左到右枚举操作区间,用 set 维护当前区间排序后的结果。然后我们一位一位把 set 里的值和原序列匹配,找到第一个被改变的位置和它被改成的值,更新答案。

这样做时间复杂度不对,但是我们发现:如果 \([L,R]\) 有一段前缀排序后不动,那 \([L+1,R+1]\) 的这段前缀(长度减了 \(1\))排序后要么还是这段不动,要么后面来了个很小的数让不动的区间变短了。总之不会让不动的位置更靠后。

所以每次匹配完把不动的前缀跳过去不枚举即可,一共匹配了 \(n\) 次,时间复杂度 \(O(n\log n)\)

代码是 Solution 2。

const int N=2e5+5,inf=1e9;
int n,k;
int a[N],flag[N];
int main()
{n=read(),k=read();for(int i=1;i<=n;i++) a[i]=read();set<int> s;for(int i=1;i<=k;i++) s.insert(a[i]);int mx=0,ans=0;for(int st=1;st<=n-k+1;st++){if(st!=1) s.insert(a[st+k-1]),s.erase(a[st-1]);if(flag[st]) continue;auto it=s.begin(); int len=0;for(int j=st;j<=st+k-1;j++){if((*it)!=a[j]) {len=j;break;}it++;}if(!len) mx=inf,ans=st;for(int i=st+1;i<=len;i++) flag[i]=1;if(len>mx) mx=len,ans=st;}sort(a+ans,a+ans+k);for(int i=1;i<=n;i++) printf("%d ",a[i]);printf("\n");return 0;
}

C. Social Distance on Graph

C < B,简单题。

Description

给一张 \(n\) 个点 \(m\) 条边的无向带权图,你要给每个点染黑色或白色。要求对于任意起点终点同色的简单路径,路径的长度(即边权和)不小于 \(X\)。求 \(X\) 的最大值。

保证图连通、无重边无自环,\(N,M \le 2\times 10^5\)\(1\le W_i\le 10^9\)

Solution

长度最小的路径肯定是只有一条边的路径,我们希望这样的路径尽量不连接相同颜色的点,并让边权小的优先满足条件。

发现这个本质上是对原图跑最小生成树,跑完的这棵树一定是二分图,且优先令边权小的边满足了条件。对最小生成树黑白染色,判断未被加入的边两个端点颜色是否相同。若相同,则答案对该边权取 \(\min\)

考虑路径长度不为 \(1\) 的情况,发现最小生成树上路径长度为 \(2\) 的边一定属于同一颜色。对每个点记录与它相连的最小边和次小边,并用它们更新答案。同时你发现这东西是答案上界,最多只有 \(2\times 10^9\),不用开 long long。

const int N=2e5+5,inf=2e9;
int n,m;
struct node{int u,v,w;}E[N];
bool cmp(node x,node y) {return x.w<y.w;}
struct edge{int to,w;};
vector<edge> e[N];
bool cmp1(edge x,edge y) {return x.w<y.w;}
int fa[N];
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
int col[N],flag[N];
void dfs(int u)
{for(auto i:e[u]){int v=i.to;if(col[v]==-1) col[v]=col[u]^1,dfs(v);}
}
int main()
{n=read(),m=read();for(int i=1;i<=m;i++) E[i]={read(),read(),read()};sort(E+1,E+m+1,cmp);for(int i=1;i<=n;i++) fa[i]=i,col[i]=-1;for(int i=1;i<=m;i++){int u=E[i].u,v=E[i].v,w=E[i].w;if(find(u)==find(v)) {flag[i]=1;continue;}fa[find(u)]=find(v);e[u].push_back({v,w}),e[v].push_back({u,w});}for(int i=1;i<=n;i++) if(find(i)==i) col[i]=0,dfs(i);int ans=inf;for(int i=1;i<=m;i++){if(flag[i]) if(col[E[i].u]==col[E[i].v]) ans=min(ans,E[i].w);}for(int i=1;i<=n;i++) sort(e[i].begin(),e[i].end(),cmp1);for(int i=1;i<=n;i++)if(e[i].size()>1) ans=min(ans,e[i][0].w+e[i][1].w);printf("%d\n",ans);return 0;
}

D. Substring Comparison

Description

构造一个长度为 \(n\) 的整数序列 \(X\),使其满足 \(m\) 条限制。第 \(i\) 条限制形如 \((A_i,B_i,C_i,D_i)\),表示要求 \(X\) 的子段 \([A_i,B_i]\) 字典序小于 \([C_i,D_i]\)。问是否存在满足条件的序列 \(X\)

\(n,m\le 2000\)

Solution

对于 \(A_i=C_i\) 的询问,可以直接比较 \(B_i\)\(D_i\) 的大小,\(B_i>D_i\) 则无解,否则这个限制一定满足,可以忽略。因此,我们假设所有询问满足 \(A_i\neq C_i\)

我们希望每组限制的两个区间在尽量靠前的位置上就开始不一样,因为这样后面的位就都没有大小限制。看到判断若干点之间的大小关系能否满足,考虑建图。

对每组限制连边 \(A_i\to C_i\),表示对于 \(X\) 有限制 \(X_{A_i}\le X_{C_i}\)。那么连出的这个图分两种情况:

  • 图里没有环,则直接按拓扑序给 \(X\) 的每个位置赋值即可,答案为 Yes
  • 图里有环,需要做进一步考虑。

对于在同一个强连通分量内的点,要满足图连边的大小关系,它们的 \(X\) 值必须都相等。因此可以对这个图跑 tarjan 求出强连通分量,并重新依次考虑题目给出的每个限制:

  • 如果 \(A_i\)\(C_i\) 不在一个强连通分量,那么它们所在位置的 \(X\) 值不相等,这个字典序的条件已经满足了;
  • 否则,代表 \(X_{A_i}\)\(X_{C_i}\) 一定是相等的,需要限制它们下一位的大小关系。我们令 \(A_i\gets A_i+1,C_i\gets C_i+1\),并在缩点后的图上重新建图,重复以上步骤。
  • 如果一直重复到 \(A_i=B_i\)\(C_i=D_i\) 它们都只能相等,判断哪个区间还剩下一段,如果是前面的区间剩一段就无解。否则这个限制已经满足。

如果重复完了上述步骤,中途没有被判无解,就是有解。

每次重复该过程都会让当前未满足限制的 \(A_i\gets A_i+1\),至多重复 \(n\) 次。每次跑一个 tarjan,复杂度 \(O(n+m)\)。总复杂度 \(O(n^2+nm)\)

代码为了好写用并查集维护了哪些点值相等,但这不是复杂度瓶颈。

const int N=2005;
int n,m,fa[N];
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
il void merge(int x,int y) {if(find(x)!=find(y)) fa[find(x)]=find(y);}
struct edge{int nxt,to;}e[N<<1];
int head[N],cnt;
il void add(int u,int v) {e[++cnt]={head[u],v};head[u]=cnt;}
int dfn[N],low[N],in[N],tot;
stack<int> Q;
bool flag;
void tarjan(int u)
{dfn[u]=low[u]=++tot,in[u]=1; Q.push(u);for(int i=head[u];i;i=e[i].nxt){int v=e[i].to;if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);else if(in[v]) low[u]=min(low[u],dfn[v]);}if(dfn[u]==low[u]){while(!Q.empty()){int t=Q.top(); if(t!=u) flag=1;merge(t,u),in[t]=0,Q.pop();if(t==u) break;}}
}
il void clear() 
{memset(head,0,sizeof(head)),cnt=0;memset(dfn,0,sizeof(dfn)),memset(low,0,sizeof(low)),tot=0;    
}
struct node{int a,b,c,d;} q[N];
int main()
{n=read(),m=read();for(int i=1;i<=m;i++) q[i]={read(),read(),read(),read()};for(int i=1;i<=n;i++) fa[i]=i;for(int w=1;w<=n;w++){clear();for(int i=1;i<=m;i++){while(find(q[i].a)==find(q[i].c)&&q[i].a<=q[i].b&&q[i].c<=q[i].d)q[i].a++,q[i].c++;if(q[i].c>q[i].d) {printf("No\n");return 0;}if(q[i].a<=q[i].b) add(find(q[i].a),find(q[i].c));}flag=0;for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);if(!flag) break;}printf("Yes\n");return 0;
}

E. Random Isolation

好厉害的题,不会做。看了官方题解。

Description

给一棵 \(n\) 个节点的树和一个整数 \(K\)。每次操作,等概率随机选一个所在连通块大小大于 \(K\) 的点,并删掉这个点和与之相连的所有边。重复操作直到图上所有连通块大小不超过 \(K\),求期望操作次数,答案对 \(998244353\) 取模。

\(1\le K < N\le 100\)

Solution

将题目的操作转化为:对于随机的长度为 \(n\) 的排列 \(p\),我们按 \(p_1,p_2,\dots,p_n\) 的顺序依次考虑。若 \(p_i\) 所在连通块的大小大于 \(K\),那么在当前的树上删除 \(p_i\);否则不进行任何操作。求有效操作的期望次数。

考虑为什么这和原问题是等价的。忽略掉所有无效的操作,则当前局面下,所有可以有效操作的点在下一步被选取的概率均相等。而对于这步无效的点显然不会后面删着删着变有效了,所以它在哪里都对期望次数没有影响。

\(p(T)\) 表示原树的子树 \(T\) 恰好在删的过程中作为完整的连通块出现的概率。根据期望的线性性,我们考虑每棵子树对答案的贡献。对于一个 \(size>K\) 的子树 \(T\),它一定要在 \(T\) 形态下被操作一次,对答案的期望产生 \(1\times p(T)\) 的贡献。而经过这次操作后,\(T\) 就不再是 \(T\),它变成了若干棵别的子树,这部分的贡献已经被它变成的新子树统计了。也就是说,每个 \(T\) 对期望次数的贡献是 \(p(T)\)。答案的总期望为 \(\sum\limits_{size_T>K} p(T)\)

问题瓶颈变成怎么求 \(p(T)\)。我们设 \(size_T=n\),与 \(T\) 里的点有边直接相连,且不属于 \(T\) 的点有 \(m\) 个。即,\(T\) 向子树外有 \(m\) 条直接连边。

那么根据 \(T\) 独立存在的条件,我们知道:\(T\) 内的 \(n\) 个点都还没被操作,且与 \(T\) 相连的这 \(m\) 个点都被操作过了。回到一开始把操作转化成的排列,上述条件等价于:某 \(m\) 个点在排列上的位置均在某 \(n\) 个点前面。不难得出这个的概率为 \(\dfrac{n!m!}{(n+m)!}\)

剩下的最后一个问题是如何对 \(T\) 进行计数。发现 \(T\) 对答案的贡献只与 \(n\)\(m\) 的值有关,考虑基于这点合并统计 \(n\)\(m\) 均相等的子树的数量,可以树形 DP。

\(f_{u,i,j}\) 表示以点 \(u\) 为根,点数为 \(i\),且 不包括 \(u\) 的父亲 与之相连的点数为 \(j\) 的连通块个数。这么设是因为把 \(u\) 的父亲也算进去,向上转移又要减掉这部分贡献很麻烦。

树形背包转移即可,式子这里不写了。时间复杂度是 \(O(n^2K^2)\)

#define int long long
const int N=105,mod=998244353;
int n,K;
int f[N][N][N];
struct edge{int nxt,to;}e[N<<1];
int head[N],cnt;
il void add(int u,int v) {e[++cnt]={head[u],v};head[u]=cnt;}
int siz[N],jc[N<<1],inv[N<<1];
il int qpow(int n,int k=mod-2)
{int res=1;for(;k;n=n*n%mod,k>>=1) if(k&1) res=res*n%mod;return res;
}
il void init(int n)
{jc[0]=inv[0]=1;for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;inv[n]=qpow(jc[n]);for(int i=n-1;i;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
int tmp[N][N];
void dfs(int u,int fa)
{f[u][1][0]=1,siz[u]=1;for(int i=head[u];i;i=e[i].nxt){int v=e[i].to; if(v==fa) continue;dfs(v,u);memset(tmp,0,sizeof(tmp));f[v][0][1]=1;for(int j=0;j<=siz[u];j++)for(int k=0;k<=siz[u];k++)for(int s=0;s<=siz[v];s++)for(int t=0;t<=siz[v];t++)tmp[j+s][k+t]=(tmp[j+s][k+t]+f[u][j][k]*f[v][s][t]%mod)%mod;siz[u]+=siz[v];for(int j=0;j<=siz[u];j++)for(int k=0;k<=siz[u];k++) f[u][j][k]=tmp[j][k];}
}
signed main()
{n=read(),K=read();init(2*n);for(int i=1;i<n;i++){int u=read(),v=read();add(u,v),add(v,u);}dfs(1,0);int ans=0;for(int i=1;i<=n;i++)for(int j=K+1;j<=siz[i];j++)for(int k=0;k<=siz[i];k++){int rl=k+(i!=1);ans=(ans+f[i][j][k]*jc[j]%mod*jc[rl]%mod*inv[j+rl]%mod)%mod;}printf("%lld\n",ans);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/99141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

九大装修收纳空间的设计,收藏备用!福州中宅装饰,福州装修

如果房子面积不大&#xff0c;收纳设计就显得非常重要。其实装修房子中很多地方都可以做收纳&#xff0c;九大空间每一处都可以放下你的东西&#xff0c;让你摆脱收纳烦恼。 收纳空间少的话&#xff0c;装修完后住久了怕会乱成一窝&#xff0c;因此装修的时候&#xff0c;收纳…

java spring cloud 工程企业管理软件-综合型项目管理软件-工程系统源码

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…

3D模型格式转换工具HOOPS Exchange助力Halocline开发VR

挑战&#xff1a; 支持客户群使用各种CAD系统和CAD文件格式。快速准确的加载可视化硬件数据。提供访问模型详细信息&#xff0c;同时确保高帧频性能。 结果&#xff1a; 确保支持标准文件格式和来自领先工程软件包的CAD数据。 通过查看简化模型或根据需要访问高层次的细节&am…

面试题20231008

前端 2023年前端面试题汇总-CSDN博客 后端 1.Java基础 容器、线程等等 a.JDK 和 JRE 有什么区别&#xff1f; JDK&#xff1a;Java Development Kit 的简称&#xff0c;Java 开发工具包&#xff0c;提供了 Java 的开发环境和运行环境。 JRE&#xff1a;Java Runtime Envir…

Flutter安卓混淆的相关问题

当你执行 build apk 后&#xff0c;flutter会默认进行混淆&#xff0c;若你的应用中引用了第三方的sdk&#xff0c;在debug模式下没问题&#xff0c;但在release下可能就会出现各种各样的问题&#xff0c;找不到某个类&#xff0c;或者某个功能无法使用&#xff0c;甚至直接崩溃…

【多线程案例】设计模式-单例模式

1.单例模式 什么是单例模式&#xff1f; 所谓单例&#xff0c;即单个实例。通过编码技巧约定某个类只能有唯一一个实例对象&#xff0c;并且提前在类里面创建好一个实例对象&#xff0c;把构造方法私有化&#xff0c;再对外提供获取这个实例对象的方法&#xff0c;&#xff0…

嵌入式养成计划-31-网络编程----TCP的并发服务器模型------IO模型--IO多路复用

六十七、 TCP的并发服务器模型 67.1 循环服务器模型 一次只能处理一个客户端&#xff0c;当上一个客户端退出后&#xff0c;才能处理下一个客户端缺点&#xff1a;无法同时处理多个客户端 代码模型 sfd socket(); bind(); listen(); while(1){newfd accept();while(1){re…

vue-3

一、文章内容概括 1.生命周期 生命周期介绍生命周期的四个阶段生命周期钩子声明周期案例 2.工程化开发入门 工程化开发和脚手架项目运行流程组件化组件注册 二、Vue生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09…

数据结构和算法笔记1:滑动窗口

在一些数组或者字符串我们需要遍历子序列&#xff0c;可能要用到两个指针&#xff08;我们称为起始指针和终止指针&#xff09;进行双层遍历&#xff0c;内层终止指针满足条件时跳出内层循环&#xff0c;然后起始指针前进&#xff0c;回溯终止指针到起始指针&#xff0c;以此继…

取消激光雷达/不升级Orin,小鹏P5改款背后的行业「痛点」

9月25日&#xff0c;小鹏汽车正式发布了旗下改款车型—2024款小鹏P5&#xff08;15.69-17.49万元&#xff09;。车型精简、降本增效&#xff08;减配&#xff09;成为新亮点。 在配置变化方面&#xff0c;智驾成为牺牲品。其中&#xff0c;高配Pro车型继续保留英伟达Xavier&…

CCC、ICCE和ICCOA数字钥匙协议

文章目录 一、CCC二、ICCE三、ICCOA四、比较 一、CCC CCC&#xff08;Car Connectivity Consortium&#xff09;车联网联盟是一个致力于制定智能手机到汽车连接解决方案标准的全球跨行业组织。2021年7月CCC将UWB定义为第三代数字钥匙的核心技术&#xff0c;并发布CCC R3&#…

如何领取京东优惠券用微信支付还是用支付宝支付购买商品?

京东用微信支付还是用支付宝支付&#xff1f; 京东商城购物不支持支付宝支付&#xff0c;现京东商城支持的支付方式包括&#xff1a;京东支付、银行卡、信用卡、微信支付、云闪付等&#xff1b; 京东如何领取优惠券用微信支付购物&#xff1f; 1、打开京东APP&#xff0c;挑选…

存档&改造【04】二维码操作入口设置细节自动刷新设置后的交互式网格

因为数据库中没有数据无法查看设置效果&#xff0c;于是自己创建了个测试数据表&#xff0c;用来给demo测试 -- 二维码操作入口设置 create table JM_QR_CODE(QR_CODE_ID NUMBER generated as identity primary key,SYSTEM_ID NUMBER(20) not null,IS_ENAB…

安装torchtext遇到的坑及解决办法

刚开始秉着需要什么就pip install什么的原则直接pip install torchtext&#xff0c;结果&#xff1a; 把我这个环境打乱了&#xff0c;自作主张的删掉之前的很多包重新安装了其他版本的包而不是自适应的安装当前torch所对应的torchtext。因为这个环境比较重要也用在其他的工程…

【前端设计模式】之责任链模式

引言 在前端开发中&#xff0c;我们经常需要处理复杂的请求流程&#xff0c;例如事件处理、数据验证等。这时候&#xff0c;职责链模式就能派上用场了。职责链模式允许我们将请求发送者和接收者解耦&#xff0c;并将请求沿着一个链条依次传递下去&#xff0c;直到有一个接收者…

(C++)引用的用法总结

引用&#xff08;reference&#xff09;是C极为重要的一部分&#xff0c;本文对其用法进行简单总结。 1. 引用的基本用法 引用的关键字为&&#xff0c;表示取地址的意思&#xff0c;引用变量定义如下&#xff1a; int m 1; int &n m; //定义 cout<<"n:…

【FreeRTOS】【STM32】01从零开始的freertos之旅 浏览源码下的文件夹

基于野火以及正点原子 在打开正点原子的资料pdf时&#xff0c;我遇到了pdf无法复制粘贴的问题&#xff0c;这里有个pdf解锁文字复制功能的网址&#xff0c;mark一下。超级pdf 参考资料《STM32F429FreeRTOS开发手册_V1.2》 官方资料 FreeRTOS 的源码和相应的官方书籍均可从官…

机器人中的数值优化(二十一)—— 伴随灵敏度分析、线性方程组求解器的分类和特点、优化软件

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考&#xff0c;主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等&#xff0c;本系列文章篇数较多&#xff0c;不定期更新&#xff0c;上半部分介绍无约束优化&#xff0c;…

模型训练环境相关(CUDA、PyTorch)

模型训练环境相关&#xff08;CUDA、PyTorch&#xff09; 1. 查看当前 GPU 所能支持的最高版本的 CUDA2. 如何判断是否安装了 CUDA3. 安装 PyTorch3.1 创建虚拟环境3.2 激活并进入虚拟环境3.3 安装 PyTorch 1. 查看当前 GPU 所能支持的最高版本的 CUDA 打开 NVIDIA 控制面板&a…

如何理解pytorch中的“with torch.no_grad()”?

torch.no_grad()方法就像一个循环&#xff0c;其中循环中的每个张量都将requires_grad设置为False。这意味着&#xff0c;当前与当前计算图相连的具有梯度的张量现在与当前图分离了我们将不再能够计算关于该张量的梯度。直到张量在循环内&#xff0c;它才与当前图分离。一旦用梯…