[AGC59C] Guessing Permutation for as Long as Possible

Problem Statement

A teacher has a hidden permutation P=(P1,P2,,PN) of (1,2,,N). You are going to determine it.

To do this, you prepared a sequence of pairs of integers (A1,B1),(A2,B2),,(AN(N1)/2,BN(N1)/2); this is a permutation of all pairs of the form (a,b) (1a<bN). Now, you will go over the pairs from the beginning. For a pair (Ai,Bi), you will ask if PAi<PBi, and the teacher will tell you the answer. However, you will skip this question if you can already determine the answer to it from previous answers.

Find the number of permutations P, for which with your algorithm you will have to ask all N(N1)2 questions, modulo 109+7.

Constraints

  • 2N400
  • 1Ai<BiN
  • (Ai,Bi)(Aj,Bj) (ij)
  • All values in the input are integers.

Input

Input is given from Standard Input in the following format:

$N$
$A_1$ $B_1$
$A_2$ $B_2$
$\vdots$
$A_{N(N-1)/2}$ $B_{N(N-1)/2}$

Output

Print the answer.


Sample Input 1

2
1 2

Sample Output 1

2

Clearly, for any permutation P, you need to ask 1 question.


Sample Input 2

4
1 2
1 3
2 3
2 4
3 4
1 4

Sample Output 2

4

Consider P=(2,3,1,4) as an example. In this case, you will skip the third question since you know P1<P2 and P1>P3 from previous questions and you can determine P2>P3. Therefore, P=(2,3,1,4) should not be counted.


Sample Input 3

5
1 2
2 3
3 4
4 5
1 5
1 3
2 4
3 5
1 4
2 5

会发现如果我们给每一个询问钦定了答案,那么最后的序列可以由我们钦定的答案推出。仔细想想,一个答案序列只对应一个排列,一个排列也只对应一个答案序列。所以我们去考虑有多少种钦定答案的方式。

这还不简单,2n(n1)/2 种吗。肯定不对,不对就在于会出现冲突。而且按照题目的要求,我们不能由某两个询问去推出后面的询问的答案。

如果现在有两个询问 (a,b)(b,c),他们的回答都为真的话,我们可以推断出 pa<pc,而如果询问 (a,c) 还没被问到,那就不好了。所以出现这种情况时,如果 (a,b) 为真,(b,c) 必定为假,如果 (a,b) 为假, b,c 必定为真。

那么考虑使用并查集维护。之所以不用 2-sat 是因为这里的边是双向的。知道了 (a,b) 为假时 (b,c) 必定为真,而 (b,c) 为真时 (a,b) 必然为假。可以参考上面的例子得知。并查集中一个记录为真的域,一个记录为假的域。然后把互相之间可以推出的一些关系合并。

具体而言,枚举到一个询问,枚举之前的询问,判断四个数中是否有两个相等,如果有,那就按照上面的方式连边就好了。有时候是真真连假假连,有时候是真假互相连。但这样复杂度 O(n4)

考虑优化,发现我们要四个数中有两个相等。可以用vector记录下那些询问 ai=x,哪些询问满足 bi=y。然后每次只用遍历vector中的数,分成四种情况。这样复杂度就是 O(n3).

如果最终某一个询问为真可以推出这个询问为假,无解。这个图极具对称性,如果 a1(True),a2(False),a3(True) 在一个连通块,那么 a1(False),a2(True),a3(False) 也在一个连通块。而这两种答案序列分配方式任选一个都是可以的。所以如果最后总共有 c 个连通块,答案为 2c2

#include<bits/stdc++.h>
using namespace std;
const int N=805,P=1e9+7;
int fa[N*N],n,v[N][N],m,a[N*N],b[N*N],cnt,pw=1;
vector<int>ga[N],gb[N];
int find(int x)
{
	if(fa[x]==x)
		return x;
	return fa[x]=find(fa[x]);
}
int main()
{
	scanf("%d",&n),m=n*(n-1)/2;
	for(int i=1;i<=m;i++)
	{
//		printf("%d\n",i);
		fa[i]=i,fa[i+m]=i+m;
		scanf("%d%d",&a[i],&b[i]);
		v[a[i]][b[i]]=v[b[i]][a[i]]=1;
		for(int j=0;j<ga[a[i]].size();j++)
		{
			if(!v[b[i]][b[ga[a[i]][j]]])
			{
				fa[find(ga[a[i]][j]+m)]=find(i+m);
				fa[find(ga[a[i]][j])]=find(i);
			}
		}
//		puts("hjhyyds");
		for(int j=0;j<gb[b[i]].size();j++)
		{
			if(!v[a[i]][a[gb[b[i]][j]]])
			{
				fa[find(gb[b[i]][j]+m)]=find(i+m);
				fa[find(gb[b[i]][j])]=find(i);
			}
		}
//		puts("hjhakioi");
		for(int j=0;j<ga[b[i]].size();j++)
		{
			if(!v[a[i]][b[ga[b[i]][j]]])
			{
				fa[find(ga[b[i]][j]+m)]=find(i);
				fa[find(ga[b[i]][j])]=find(i+m);
			}
		}
//		puts("qzmyyds");
		for(int j=0;j<gb[a[i]].size();j++)
		{
			if(!v[b[i]][a[gb[a[i]][j]]])
			{
				fa[find(gb[a[i]][j]+m)]=find(i);
				fa[find(gb[a[i]][j])]=find(i+m);
			}
		}
//		puts("qzmakioi");
		ga[a[i]].push_back(i);
		gb[b[i]].push_back(i);
//		for(int j=1;j<i;j++)
//		{
//			if(a[i]==b[j]&&!v[a[j]][b[i]]||a[j]==b[i]&&!v[a[i]][b[j]])
//			{
//				fa[find(i+m)]=find(j);
//				fa[find(i)]=find(j+m);
//			}
//		}
	}
	for(int i=1;i<=2*m;i++)
	{
		if(find(i)==find(i+m))
		{
			puts("0");
			return 0;
		}
		if(fa[i]==i)
			++cnt;
	}
	for(int i=1;i<=cnt/2;i++)
		(pw<<=1)%=P;
	printf("%d",pw);
}
posted @   灰鲭鲨  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示