luogu 3 月月赛 I & EE Round 1 Div.1

这两天写题越来越有感觉了。

Div.1 A

一通乱猜,得到结论:当没有 \(1\) 的时候,答案是 \(\sum a_ia_{i+1}+\min a_i\)

也就是从左往右消到最小值的左边,然后从右往左消到最小值的右边,最后消掉最小值。

对原序列每个没有 \(1\) 的极长子段按刚才的式子算一下,然后把 \(1\) 的个数加上去,就好了。

证明不难。

Div.1 B

这是大力出奇迹题,考场不敢开大数组获得整整 30 分!

打表可知,\(p|a_p\) 当且仅当 \(p|(k+1)\)

证明:

不会,咕咕咕。

n 以内除给定数以外所有质数的乘积就是答案,线筛就好。

据说 min25 能筛出来……先咕着。

Div.1 C

这题挺好的。

先考虑没有 \(-1\) 的情况怎么做。

首先根据输入的信息,容易知道到每个位置的时候单调栈里面都有哪些下标。

考虑下标 \(i<j_1<j_2<\cdots <j_k\) 中,\(j_1,j_2,\cdots,j_k\) 曾经先后在单调栈里恰好压在 \(i\) 头顶上。

那么必有 \(p_i<p_{j_k}<p_{j_{k-1}}<\cdots <p_{j_1}\)

而只要一个排列满足以上条件,那么这个排列就一定是符合题意的。

考虑构造。从 \(0\) 向在栈底待过的下标连边,对每个 \(i\) ,从 \(i\) 按顺序向 \(j_1,j_2,\cdots,j_k\) 连边。

你发现这样构成了一棵 \((n+1)\) 个点的树。这棵树满足父亲小于儿子,且 对同一个父亲 编号大的儿子小于编号小的儿子。

考虑到要字典序最小,那么编号小的 \(i\) 所获得的 \(p_i\) 要更小。

对这棵树 DFS 一遍,每到一个点,从后往前确定每个儿子填什么,然后从前往后进儿子,递归执行。(具体参考代码)

似乎还没说 \(-1\) 怎么做。设 \(a_i=-1\) ,那 \(a_i\leftarrow a_{i-1}+1\) 就好了。容易证明这样没有问题。

#include<cstdio>
#include<vector>
const int N=1e6+3;
int n,a[N],st[N],s[N],k;
std::vector<int>g[N];
void Dfs(int i){
	if(g[i].size())for(int j=g[i].size()-1;~j;j--)s[g[i][j]]=++k;
	for(int j=0;j<g[i].size();j++){
	  Dfs(g[i][j]);
	}
}
signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
	  scanf("%d",a+i);
	  if(a[i]<0)a[i]=a[i-1]+1;
	}
	for(int i=1;i<=n;i++){
	  for(;k+1>a[i];--k);
	  g[st[k]].push_back(i);
	  st[++k]=i;
	}
	k=0;
	Dfs(0);
	for(int i=1;i<=n;i++)printf("%d ",s[i]);puts("");
	return 0;
}

posted on 2020-03-08 18:26  Dreamunk  阅读(171)  评论(0编辑  收藏  举报

导航