ATcoder 做题记录

ABC277 F

首先我们可以发现行与行、列与列之间的相对大小关系是不会相互影响的。换言之,两种操作是互相独立的

对于两种操作,我们分别来考虑。

  1. 行操作:我们找到每一行和每一列的最小值和最大值,将其排序后检查是否符合要求即可。
  2. 列操作:这个相对而言就要麻烦一些了,这题可以转化为图论模型。对于第 i 列,如果存在一列 j 满足 j>i ,但是存在 k 使得 ak,i>ak,j 我们就从 ij 连一条有向边,表示第 i 列应该要换到第 j 列的后面。如果建出来的图有环,则显然无解,反之则有解。

但是第二种操作的建图时间和空间都是我们没有办法承受的,我们考虑优化建图。

我们不管权值为 0 的点,将每一列都视为一个结点。考虑对于每一行,对于一段权值相同的点,我们建一个新点,向这些点表示的列连边,这些点向之后的第一个新点连边。这样建出来的图就是等效的了,我们直接拓扑排序即可。

ABC273 F

  • 简要题意

一个人要沿数轴从 0 处走到 x 处,数轴上有一些障碍,每个障碍有一把对应的锤子可以将其销毁,给定障碍和锤子的坐标及 x ,求最短路长。

  • 简要题解

区间 DP 的思想,设 dp[l][r][0] 为遍历完 [l,r] 的坐标,并且位于 l 位置,的到达 x 的最短路长;dp[l][r][1] 为位于 r 处,直接记搜转移即可。

ABC272 F

  • 简要题意

给定两个长度为 n 的字符串 S,T,定义 f(S,i) 为将 S 的前 i 个字符依次拼到末尾形成的字符串。

问有多少二元组 (i,j) 满足 f(S,i) 的字典序小于 f(T,j)

  • 简要题解

将两个字符串都拉两倍后拼在一起跑 SA ,那么此时已经按照字典序排好序了,维护一个后缀和统计答案即可。

ABC270 F

  • 简要题意

n 个初始互不联通的岛屿,你有如下方法让其联通。

  1. 对于每个点 i ,你可以花费 ai 在该点修机场。两点如果都有机场,那这两点可以互相到达。
  2. 对于每个点 i ,你可以花费 bi 在该点修港口。两点如果都有港口,那这两点可以互相到达。
  3. m 条道路,第 i 条道路连接 ui,vi ,你可以花费 wi 让开通这条道路,开通后,道路的两个端点可以互相到达。
  • 简要题解

看着就很像一个最小生成树的题目,对于在点上有代价的,我们可以通过新建点再向该点连边的方式来实现。

具体的,对于机场,我们连边 i>n+1 ,边权为 ai ;对于港口,我们连边 i>n+2 ,边权为 bi ;对于道路正常连边,然后跑最小生成树即可。

点击查看代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e5+5;
const LL inf=0x3f3f3f3f3f3f3f3f;

inline int read() {
	int x=0,w=0; char ch=getchar();
	while(!isdigit(ch)) w|=(ch=='-'), ch=getchar();
	while(isdigit(ch)) x=x*10+(ch^48), ch=getchar();
	return w?-x:x;
}

struct edge { int x,y,z; bool friend operator<(edge x,edge y) { return x.z<y.z; } }e[N<<2];
int n,m,idx,a[N],b[N],u[N],v[N],w[N],fa[N];
LL ans=inf;

inline int Get(int x) { return fa[x]==x?x:fa[x]=Get(fa[x]); }

inline LL Kruskal(int n) {
	for(int i=1;i<=n;i++) fa[i]=i;
	sort(e+1,e+1+idx);
	LL res=0,cnt=0;
	for(int i=1,fx,fy;i<=idx && cnt<n-1;i++) {
		fx=Get(e[i].x); fy=Get(e[i].y);
		if(fx^fy) fa[fx]=fy, ++cnt, res+=e[i].z;
	}
	return cnt==n-1?res:inf;
}

int main() {
	n=read(); m=read();
	for(int i=1;i<=n;i++) a[i]=read(); 
	for(int i=1;i<=n;i++) b[i]=read();
	for(int i=1;i<=m;i++) u[i]=read(), v[i]=read(), w[i]=read();
	for(int k=0,node;k<4;k++) {
		node=n; idx=0;
		if(k&1) { ++node; for(int i=1;i<=n;i++) e[++idx]=edge{i,node,a[i]}; }
		if(k&2) { ++node; for(int i=1;i<=n;i++) e[++idx]=edge{i,node,b[i]}; }
		for(int i=1;i<=m;i++) e[++idx]=edge{u[i],v[i],w[i]};
		ans=min(ans,Kruskal(node));
	}
	cout<<ans<<endl;
	return 0;
}

ABC243 F

  • 简要题意:

n 个物品,可以随机抽 k 轮,每轮相互独立且抽中物品 i 的概率为 pi ,问最终恰好抽到 m 个不同的物品的概率。

m 个 物品,每个物品可以重复选,最终选择恰好 n 个物品的概率(无标号) P=n!i=1mci!

  • 简要题解

设考虑完 x 个物品,共选择了 y 个不同的物品,已经选择了 z 次的概率为 f[x][y][z] ,那么每次转移枚举第 x+1 个物品选择多少个即可。转移方程:

px+1cc!f[x][y][z]>f[x+1][y+[c!=1]][z+c])

ABC238 F

考虑按照第一次考试的排名从前往后排序。我们设 f[i][j][k] 表示考虑完前 i 个人,选择了 j 个人,选择的人中第二次考试最靠前的排名为 k 的方案数。

转移比较容易。

显然有 f[i][j][k]>f[i+1][j][k] 表示不选择这个人。

如果满足 这个人第二次考试的排名比 k 靠前,那么有 f[i][j][k]>f[i+1][j+1][Qi]

posted @   _YangZJ  阅读(72)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩