[CF1343F]Restore the Permutation by Sorted Segments

题目

传送门 to luogu

思路

有两个很强的限制:

  • l < r ll<r 。注意这里是严格小于!所以长度至少为 2 2 2
  • { r i } = { 2 , 3 , 4 , … , n } \{r_i\}=\{2,3,4,\dots,n\} {ri}={2,3,4,,n} 。也就是说,每个“片段”是 各个前缀 的一部分。

第二个条件会是可爱的突破口。显然,如果我们知道每一个前缀,那么就能完整确定这个序列。虽然“片段”只是前缀中的一部分,也很不错了。那么我们枚举第一个前缀吧!也就是 第一个元素

知道了前缀 x x x ,怎么确定下一位?用已知的“片段”。如果一个“片段”中,它只有一个元素还没有出现,并且剩下的元素都出现在最靠后的部分,那么我们有理由相信,这个“片段”是前缀 x + 1 x+1 x+1 的一部分。所以这个唯一的元素当然是第 x + 1 x+1 x+1 个元素啦!

正确性是显然的,上面的构造方法保证了每一个“片段”都被满足。又因为第一条,对于正确的序列,只剩一个元素的前缀只有一个。

复杂度分为三部分,枚举第一个元素、逐位确定、查看“片段”。分别是 n , n n,n n,n n 2 n^2 n2 。总复杂度 O ( n 4 ) \mathcal O(n^4) O(n4) ,很难跑满,因为中途就会因为找不到下一位元素而退出。

代码

#include 
#include 
#include 
using namespace std;
typedef long long int_;
inline int_ readint(){
	int_ a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

const int MaxN = 205;
int a[MaxN][MaxN], n;
void input(){
	n = readint();
	for(int i=1; i<n; ++i){
		a[i][0] = readint();
		for(int j=1; j<=a[i][0]; ++j)
			a[i][j] = readint();
	}
}

int ans[MaxN], id[MaxN];
void solve(){
	for(int o=1; o<=n; ++o){ // 枚举开头
		for(int i=1; i<=n; ++i)
			id[i] = 0, ans[i] = 0; // clear
		ans[1] = o, id[o] = 1;
		for(int i=2; i<=n; ++i){
			for(int j=1; j<n; ++j){
				int cnt = a[j][0], x = -1;
				for(int k=1; k<=a[j][0]; ++k)
					if(i-a[j][0] < id[a[j][k]])
						-- cnt;
					else if(!id[a[j][k]])
						x = a[j][k];
				if(cnt == 1 && ~x){
					ans[i] = x, id[x] = i; break;
				}
			}
			if(ans[i] == 0) break; // 找不到
		}
		if(ans[n] != 0) break; // 找到解了
	}
// printf("ANS: ");
	for(int i=1; i<=n; ++i)
		printf("%d ",ans[i]);
	putchar('\n');
}

int main(){
	for(int T=readint(); T; --T)
		input(), solve();
	return 0;
}

你可能感兴趣的:(C++)