DTOJ 2022.11.07 测试 题解

A

portal

题目大意

长度为 \(n\) 的数列,给 \(m\) 条信息:从 \(x,y\) 开始的最长公共前缀的长度是 \(z\),要求字典序最小.

\(1 \le m \le 1000\)\(1 \le n \le 1000\)

题解

每个信息可以被拆成最多 \(n\) 条信息,\(a_x=a_y,\ a_{x+1}=a_{y+1},\cdots,a_{x+z-1}=a_{y+z-1},a_{x+z}\ne a_{y+z}\)

这些是很好用并查集维护的.

首先把相等的下标合并起来,再判一下有没有不等关系在相同集合里,就可以判断可行性.

现在考虑字典序怎么最小.

直接把所有不等关系存起来,从前往后贪心填,每一个位置直接填最小合法的数就好了.

因为字典序本质就是贪心的所以这样一定就是对的.

测试的时候写挂了,但是后面经提醒改了((

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1005;
int n,m;
int fa[N],x[N],y[N],z[N],dat[N],v[N],cd;
int get(int x) { return x==fa[x]?x:(fa[x]=get(fa[x])); }
void merge(int x, int y) { x=get(x),y=get(y); if(x<y) swap(x,y); if(x!=y) fa[x]=y; }
vector<int> g[N];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++) fa[i]=i;
	for(int i=1; i<=m; i++) scanf("%d%d%d",&x[i],&y[i],&z[i]);
	for(int i=1; i<=m; i++) for(int j=1; j<=z[i]; j++) merge(x[i]+j-1,y[i]+j-1);
	for(int i=1; i<=m; i++)
		if(x[i]+z[i]<=n and y[i]+z[i]<=n)
		{
			int tx=get(x[i]+z[i]),ty=get(y[i]+z[i]);
			if(tx==ty) { puts("-1"); return 0; }
			g[tx].push_back(ty),g[ty].push_back(tx);
		}
	//for(int i=1; i<=n; i++) printf("%d ",get(i)); puts("");
	//for(int i=1; i<=2; i++) for(int v:g[i]) printf("%d -> %d\n",i,v);
	for(int i=1; i<=n; i++) dat[i]=-1;
	for(int i=1; i<=n; i++)
	{
		int x=get(i);
		for(int j=0; j<N; j++) v[j]=0;
		if(dat[x]==-1) 
		{
			for(int y:g[x]) if(y<x) v[dat[y]]=1;
			for(int j=0; j<N; j++) if(v[j]==0) { dat[x]=j; break; }
		}
		dat[i]=dat[x];
	}
	for(int i=1; i<=n; i++) printf("%d ",dat[i]); puts("");
	return 0;
}

B

portal

题解

bfs 求连通块,建边,每次询问暴力跑 dfs/bfs,看可达与否就好了

不知道为什么放在 B。。

二维压一维越来越熟练了hhh(写了好多这样的

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e4+5;
int n,m,k,q;
int a[N],col[N],nc;
vector<int> g[N];
int vis[N];

struct point
{
	int x,y;
	void rd() { scanf("%d%d",&x,&y); }
	friend point operator+ (point A, point B) { return {A.x+B.x,A.y+B.y}; }
} dir[]={{1,0},{0,1},{-1,0},{0,-1}};
int F(point P) { return (P.x-1)*m+P.y; }
point G(int t) { return {(t-1)/m+1,(t-1)%m+1}; }

void bfs(point S, int c)
{
	queue<point> q;
	q.push(S); col[F(S)]=c;
	auto check = [&] (const point &P) { return 1<=P.x and P.x<=n and 1<=P.y and P.y<=m and !col[F(P)] and a[F(P)]; };
	while(!q.empty())
	{
		point x=q.front(); q.pop();
		for(int i=0; i<4; i++)
		{
			point y=x+dir[i];
			if(!check(y)) continue;
			col[F(y)]=c; q.push(y);
		}
	}
}
void bfs2(int S, int c)
{
	queue<int> q;
	q.push(S);
	while(!q.empty())
	{
		int u=q.front(); q.pop();
		for(int v:g[u]) if(vis[v]!=c) vis[v]=c,q.push(v);
	}
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&k,&q);
	char ch=getchar();
	for(int i=1; i<=n*m; )
	{
		while(ch!='.' and ch!='#') ch=getchar();
		a[i++]=(ch=='.'); ch=getchar();
	}
	for(int i=1; i<=n; i++) for(int j=1; j<=m; j++)
		if(a[F({i,j})] and !col[F({i,j})]) bfs({i,j},++nc);
	nc--;
	point u,v;
	for(int i=1; i<=k; i++)
	{
		u.rd(),v.rd();
		int tu=col[F(u)],tv=col[F(v)];
		if(tu!=tv) g[tu].push_back(tv);
	}
	for(int i=1; i<=q; i++)
	{
		u.rd(),v.rd();
		int tu=col[F(u)],tv=col[F(v)];
		if(tu==tv) puts("1");
		else bfs2(tu,i),printf("%d\n",(vis[tv]==i));
	}
	return 0;
}

C

第一眼维护凸壳,但是发现很难很难维护

这题应该用李超线段树或者cdq分治

但是 cdq 还没写过

应该会补一个李超线段树写法(

D

不可写

矩阵树定理

还没学

posted @ 2022-11-13 16:31  copper_carbonate  阅读(20)  评论(0编辑  收藏  举报