11.8 模拟赛小记

发布时间 2023-11-09 17:26:58作者: Moyyer_suiy

僕を連れてって,浸み込んでしまう前に


菜哭了。不会打,看了半个小时史铁生散文集。

100+0+80+0 喵。


A.俨俨与道路(constructure)

正解是最小生成树。我的思路差不多。

为了全部联通,需要 n-1 条边。随意先计算给定的确定起始点的边,根据边权排序,从中挑至少 \(n-1-k\) 条边。剩下的用第二种边,每加一条边就能将两个联通块合并。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+10;
ll ans;
int n,m,k,w,cnt; 
int fa[N];
struct node{int u,v,z;}r[N];
bool cmp(node a,node b){return a.z<b.z;}
int fd(int x){
	if(fa[x]==x) return x;
	return fa[x]=fd(fa[x]);
}
void mer(int x,int y,int z){
	x=fd(x),y=fd(y);
	if(x==y) return;
	fa[x]=y;
	ans+=z;
	cnt++;
}
int main(){
	freopen("constructure.in","r",stdin);
	freopen("constructure.out","w",stdout);
	scanf("%d%d%d%d",&n,&m,&k,&w);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&r[i].u,&r[i].v,&r[i].z);
	sort(r+1,r+m+1,cmp);
	for(int i=1;i<=m;i++){
		if(r[i].z>w&&cnt>=n-1-k) break;
		mer(r[i].u,r[i].v,r[i].z);
	}
	for(int i=1;i<=n;i++)
		if(fd(i)==i) ans+=w;
	ans-=w;
	printf("%lld",ans);
} 

B.猫猫和矩阵(makrix)

求最大面积的矩阵,该矩阵的所有子矩阵均满足对任意 \(i,j\) 都有 \(A_{1,1}+A_{i,j}<=A_{1,j}+A_{i,1}\)

赛时暴力写了 N 的好多好多好多次方然后把自己气笑了,再没看这个题。

正解,考虑先从小的角度入手,显然 \(1*n\) 的矩阵和 \(n*1\) 的矩阵都是满足要求的;再去想 \(2*n\) 的矩阵:

整理发现,为了确定这个矩阵是否满足条件,实质上是在求这个矩阵中除了最后一行、最后一列,以其他所有点为左上角的 \(2*2\) 的子矩阵是否满足。

这其实是通过归纳法来证明结论。由小见大。

然后问题转换为了:对于每个点为 \(2*2\) 子矩阵的左上角来预处理这个点是否合法。最后求面积最大的矩阵,实际上就是求最大全 1 矩阵面积。

这就是一个很典的单调栈问题了。在这篇博客里我有再整理单调栈。

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n,m;
int a[N][N],b[N][N];
int g[N],s[N],w[N],top,ans;
struct node{int g,wz;}S[N];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) scanf("%d",&b[i][j]);
	for(int i=1;i<n;i++){
		for(int j=1;j<m;j++){
			if(b[i][j]+b[i+1][j+1]<=b[i][j+1]+b[i+1][j]) a[i][j]=1;
			else a[i][j]=0;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if((a[i][j]==a[i-1][j]||i==1)&&a[i][j]) g[j]++;
			else if(a[i][j]) g[j]=1;
			else g[j]=0;
		}
		top=0;
		g[m+1]=0;
		for(int j=1;j<=m+1;j++){
			int kuan=0;
			while(g[j]<s[top]){
				kuan+=w[top];
				ans=max(ans,(kuan+1)*(s[top]+1));
				top--;
			}
			s[++top]=g[j];
			w[top]=kuan+1;
		}
	}
	ans=max(ans,max(n,m));
	printf("%d",ans);
}

C.猫猫和排列(inversion)

给一个由 \([1,n]\) 构成的排列,求一个逆序对数与之相同,且字典序比之大的字典序最小的序列。

没想到吧,next_permutation 暴力枚举序列竟然有 80pts。

找到一个位置 i,使前 i-1 与原序列相同。可以二分出 i,使答案序列 1~i-1位与原序列相同,后面的也是确定的所以也可以二分。

因为我不太懂啊。所以鸽了,没补。


D.猫猫分糖果(divide)

好像,多少和博弈论沾些边了。所以我不补。