zoukankan      html  css  js  c++  java
  • 【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
    ",f[n+1]);
    }
    
  • 相关阅读:
    day 3 python 函数 -- lambda -- 内置函数 -- 进制转换
    day 2 基本类型和函数
    linux 的常用命令
    python & diretory 对象
    python & list对象
    python & str对象函数
    python全栈之路 1 python的基本介绍
    centos6.5 配置SSH
    js禁止高频率连续点击思路
    $.ajax参数备注-转转转
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9745300.html
Copyright © 2011-2022 走看看