【CF Gym100228】Graph of Inversions

Portal --> qwq(貌似是CodeForces Gym 100228 (ECNA2003) - I)

Description

  对于长度为 \(n\) 的序列 \(A\) ,定义其逆序图 \(G\) 如下:无向图 \(G\)\(n\) 个节点,编号为 \(0..n-1\) ;对于任意的$ 0≤i<j≤n−1$ ,如果有 \(a[i]>a[j]\),那么 \(G\)中存在一条 \(i\)\(j\)之间的边。例如:\(A=\{1,3,4,0,2\}, G=\{(0,3),(1,3),(1,4),(2,3),(2,4)\}\)
​  定义独立集 \(S\):对于\(∀x∈S,y∈S\) ,都不存在一条边$ (x,y)$
​  定义覆盖集 \(S\) :对于\(∀x∉S\),至少存在一条边$ (x,y)$,使得 \(y∈S\)
​  现在给你一个逆序图 \(G\)(保证合法),求$ G$ 有多少个点集既是独立集又是覆盖集。

​  数据范围:\(1<=n<=1000,0<=m<=n*(n-1)/2\)

  

Solution

​  首先。。图的独立集是。。一个np问题==那所以直接在图上面搞什么的显然是不理智的qwq

  那所以。。要好好利用逆序图这个条件

  把独立集和覆盖集放在回原来的序列里面来看,其实就是:\(S\)中的元素无法构成逆序对(也就是说。。必须递增),并且任意非\(S\)元素均能与\(S\)中至少一个元素构成逆序对

​  所以我们其实是要找有多少个递增的子序列满足第二个条件

​  这个要怎么找呢。。考虑dp,记\(f[i]\)表示以\(i\)结尾的满足条件的子序列有多少个,那么考虑转移,\(f[i]\)能够转移到\(f[j]\),当且仅当满足\(a[i]<a[j]\)并且\(i\)\(j\)中间的这段都要能和子序列中的至少一个元素构成逆序对,也就是要么小于\(a[i]\)要么大于\(a[j]\),然后因为如果小于\(a[i]\)的话不满足第一个转移条件,所以\(i\)\(j\)之间的,除了之前能够转移的位置,其他肯定都是小于\(a[i]\)的不用管,我们只要看\(>a[i]\)中最大的那个是不是\(>a[j]\)就好了,具体实现其实很简单,因为这些需要单独考虑的位置肯定是之前遇到的能够转移的位置,所以我们开多一个\(tmp\)记录一下最大值即可

​  至于这个序列要怎么还原,因为只有大于和小于关系,所以。。我们钦定一下这个序列是一个\(1\)\(n\)的排列,然后我们可以通过逆序对得到每个数前面比它大的有多少个,后面比它大的有多少个,那就可以得到每个数的具体值了(为了方便统计答案我们可以将\(a[n+1]\)钦定成一个很大的数然后计算到\(n+1\)位,答案就是\(f[n+1]\)

  

​  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=1010;
struct Rec{
	int x,y;
}rec[N*(N-1)/2];
int a[N],cnt[N];
ll f[N];
int n,m,ans;
void dp(){
	int tmp;
	f[0]=1;
	for (int i=0;i<=n;++i){
		tmp=n+2;
		for (int j=i+1;j<=n+1;++j){
			if (a[j]<a[i]||a[j]>=tmp) continue;
			f[j]+=f[i];
			tmp=a[j];
		}
	}
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i) cnt[i]=n-i;
	for (int i=1;i<=m;++i){
		scanf("%d%d",&rec[i].x,&rec[i].y);
		++rec[i].x; ++rec[i].y;
		if (rec[i].x>rec[i].y) swap(rec[i].x,rec[i].y);
		++cnt[rec[i].y]; --cnt[rec[i].x];
	}
	for (int i=1;i<=n;++i) a[i]=n-cnt[i];
	a[n+1]=n+1;
	dp();
	printf("%d\n",f[n+1]);
}
posted @ 2018-10-05 17:21  yoyoball  阅读(187)  评论(0编辑  收藏  举报