牛客第十场 题解

Posted Frank_Star

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客第十场 题解相关的知识,希望对你有一定的参考价值。

比赛传送门
作者: fn


签到题

H题 War of Inazuma (Easy Version) / 稻生之战(简易版)

题目大意
给n维超立方体染色,使每个顶点相邻的点中,和这个顶点颜色相同的不超过 ⌈ n ⌉ \\lceil \\sqrt{n}\\rceil n 个。

考察内容
贪心

分析
贪心策略。第一个标记为0,之后每次在之前的基础上每位取反,然后加到末尾即可。

#include<bits/stdc++.h> // H
#define ll long long
#define cer(x) cerr<<(#x)<<" = "<<(x)<<'\\n'
using namespace std;
const int N=1e7+10;
ll n,m,a[N];

int main(){ 
	ios::sync_with_stdio(0); cin.tie(0);
	cin>>n;
	
	ll len=pow(2,n);  
	
	a[0]=0;
	int pos=1;
	for(int i=0;i<n;i++){
		ll num=pow(2,i);
		for(int j=1;j<=num;j++){
			a[pos]=1-a[pos-num];
			pos++;
		}
	}
	
	for(int i=0;i<len;i++){
		cout<<a[i];
	}
	cout<<endl;

	return 0;
}


进阶题

F题 Train Wreck / 失事列车

题目大意
旧火车站只有一条带有死胡同的轨道,它就像一个堆栈:每次你要么把一辆火车推入车站,要么把最近添加的火车弹出车站。

每天有n列火车进站出站。 检查员已经决定了今天的“推”和“弹出”的顺序。

设计一个方案,让每次进栈后的序列都不同。

输出一个解决方案。不可能时输出"NO" 。

考察内容
贪心,树的遍历,优先队列

分析
将栈操作视为树,要求转化为给每一个节点染色,使得从根到每一个节点的链所构成的颜色序列两两不同。
注意到两个都在第 i 层的节点,如果它们的父亲不同,则从根到它们父亲的链所构成的颜色序列不同,这使得从根到它们的链所构成的颜色序列一定不同。(因为删去序列最后一项后得到的序列不同)因此,条件可以转化为每个点的各个儿子颜色互不相同。
对于一个节点,假设其有 k k k 个儿子,我们选取剩余火车数最多的 k k k 个颜色对应上去。可以用优先队列实现。

#include<bits/stdc++.h>
#define eb emplace_back
using namespace std;
const int M=2e6+9;
int n,m,id;
char c[M];
int b[M],a[M],t[M],co[M];
vector<int>g[M];
void push(int x,int y){
	for(t[x+=n-1]=y;x;x>>=1)t[x>>1]=b[t[x]]>b[t[x^1]]?t[x]:t[x^1];
}
void dfs(int u){
	for(auto v:g[u]){
		co[v]=t[1];
		b[t[1]]--;
		if(b[t[1]]<0){
			puts("NO");
			exit(0);
		}
		push(co[v],0);
	}
	for(auto v:g[u]){
		push(co[v],co[v]);
	}
	for(auto v:g[u])dfs(v);
}
void out(int u){
	if(u)printf("%d ",co[u]);
	for(auto v:g[u])out(v);
}
int main(){
	scanf("%d%s",&n,c+1);
	for(int i=1;i<=n*2;++i){
		if(c[i]=='(')a[++m]=++id,g[a[m-1]].eb(a[m]);
		else m--;
	}
	for(int i=1,x;i<=n;++i)scanf("%d",&x),b[x]++,push(x,x);
	dfs(0);
	puts("YES");
	out(0);
	puts("");
	return 0;
}

A题 Browser Games / 浏览器游戏

题目大意

在即将到来的n天里,将在一个网站上发布n个浏览器游戏。每天发布一个新游戏。用户必须打开相应的URL才能下载游戏。

然而,一旦用户以某种方式找到一个未发布游戏的URL,游戏的数据就会泄露出去。为了暂时解决这个问题,管理员决定在服务器端添加一系列非空字符串作为确认前缀。当请求的URL确实对应于一个游戏(无论是否发布),并且至少有一个确认前缀是该URL的前缀时,服务器将响应正确的游戏数据;否则,服务器将声明没有找到该游戏。

输出每次新游戏发布后,服务器所需的最小确认前缀数量。

注:内存限制32mb

样例输入

3
ufoipv.ofu
hsbocmvfgboubtz.kq
hfotijo.njipzp.dpn/kb

样例输出

1
2
2 

样例解释

-在第一天,使用 “ufoipv.ofu” 作为URL的游戏已经发布,而其他两款游戏应该是不可用的。 因此,以“u”作为唯一的确认前缀是充分的。

-在第二天,用“u”和“hs”作为确认前缀就足够了。 请注意,以“u”和“h”作为确认前缀是不可行的,这可能导致使用 “hfotijo.njipzp.dpn/kb” 作为URL的游戏数据泄露。

-在最后一天,三款游戏全部发布。 因此,用“u”和“h”作为确认前缀就足够了。 注意,不允许使用空字符串作为唯一的确认前缀,因为确认前缀应该是非空的。

考察内容
字典树(trie),字符串,空间复杂度优化

分析
加强自 2020 年 ICPC 银川赛区 K 题。
首先我们不考虑空间限制,先对所有字符串建立一棵字典树,并将每个串对应字典树上的节点标为黑点,每次操作会将一个黑点变为白点,目标是将尽可能少的非根节点标红使得任意一个白点到根的路径上都有被标红的节点,且任意一个黑点到根的路径上都没有被标红的节点。
我们记录下每个点的子树里有多少个黑点,每次有一个黑点变为白点的时候,首先标红这个白点,然后我们将所有的红色标记尽可能往上推就能得到最少被标红的节点数。

为了优化空间,我们观察到字符串只有 n 个,比字典树的节点数少一个串长的系数,如果我们能缩掉只有一个儿子的非关键点,只保留 n 个关键点以及字典树上的分叉节点,就能得到只有 O ( n ) O(n) O(n) 个节点的经过压缩的字典树,从而通过此题。
我们考虑自顶向下地递归构建这棵树,并且在构建的过程中对 n 个字符串进行排序。当我们位于某个节点时,维护节点的深度信息,以及当前节点的子树中的字符串,注意到在对所有字符串排序之后,这些字符串的下标会构成一个区间,我们可以通过深度信息得到这些字符串对应位置的字符,并使用桶排序完成对区间的划分,如果能划分出多个区间则递归下去构建各个子树,否则不需要新建节点,当某个节点只剩一个串时即可退出递归过程。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
string s[N];
int id[N],ans[N],n;
bool cmp(int a,int b) {return s[a]<s[b];}
void dfs(int l,int r,int x,int k)
{
    if  (l==r)  return;
    int maxx=0,i,j;
    for(i=l,j=l; i<=r; i++)
    {
        maxx=max(maxx,id[i]);
        if(i==r||s[id[i]][k]!=s[id[i+1]][k])
        {
            ans[maxx]++,ans[x]--;
            dfs(j,i,maxx,k+1);
            j=i+1,maxx=0;
        }
    }
}
int main()
{
    cin>>n;
    for (int i=1; i<=n; i++)
        cin>>s[i],id[i]=i;
    if (n==1) {cout<<1<<endl; return 0;}
    sort(id+1,id+1+n,cmp);
    dfs(1,n,n+1,0);
    for (int i=1; i<=n; i++)
        ans[i]=ans[i-1]+ans[i],cout<<ans[i]<<endl;
    return 0;
}

以上是关于牛客第十场 题解的主要内容,如果未能解决你的问题,请参考以下文章

OR(牛客第八场)

2018多校第十场 HDU 6430 线段树合并

字符串分类问题(牛客第二场笔试)

第十场 hdu 6172 Array Challenge(矩阵快速幂)

杂题总汇HDU多校赛第十场 Videos

第十场 hdu 6178 (bfs)