CodeForces Gym 100228 Graph of Inversions

题目大意

对于一个长为$N$的序列$A$,定义它所对应的逆序图:

有$N$个点组成,标号为$1...N$的无向图,对于每一组$i,j(i<j)$若存在$A_i>A_j$则在新图中就存在一条$(A_i,A_j)$的无向边。

现在给定一个$N(N\leq 1000)$个点的图,保证它是某个序列对应的逆序图,求它有多少个点集$S$,满足$\forall x\in S,y\in S$不存在边$(x,y)$,$\forall x\notin S$至少存在一条边$(x,y)$使得$y\in S$。即求图独立覆盖集的数量。

题解

不难发现这个序列可以的转化为一个排列。

我们可以用拓扑排序整理每对数的大小关系,从而在序列上考虑这个问题。

对于第一个条件,即点集内两两没有连边,就是满足在序列上点集对应的位置恰好形成一个上升的子序列。

对于第二个条件,满足对于$\forall x\notin S$一定至少存在一个$y\in S$使得$A_x<A_y,x>y$或$A_y<A_x,x<y$。

假设$x\notin S,y\in S$,由于$\{A_y\}$为上升子序列,和$A_x$组成逆序对的是左侧最大的$A_x$和右侧最小的$A_x$,那么就是$A_y<A_x(x=max\{x\in S,x<y\})$或$A_y>A_x(x=\min\{x\in S,x>y\})$,即对于$i,j\in S,A_i$不存在$k$使得$i<k<j,A_i<A_k<A_j,k\notin S$这样就很显然了,直接$Dp$,设$F_i$表示最后一个是$i$前$i$个合法的方案数。

暴力转移即可。复杂度$O(n^2)$。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 1020
using namespace std;
LL read(){
	LL nm=0,fh=1; char cw=getchar();
	for(;!isdigit(cw);cw=getchar()) if(cw==‘-‘) fh=-fh;
	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-‘0‘);
	return nm*fh;
}
LL n,m,fs[M],nt[M*M],to[M*M],tmp,ind[M],p[M],cnt,tot,q[M],hd,tl;
LL mp[M][M],F[M],G[M],ans;
void link(LL x,LL y){nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y,ind[y]++;}
int main(){
	n=read(),m=read(),memset(fs,-1,sizeof(fs));
	while(m--) mp[read()+1][read()+1]=1;
	for(LL i=1;i<=n;i++){
		for(LL j=i+1;j<=n;j++)	if(mp[i][j]||mp[j][i]) link(j,i);else link(i,j);
	}
	for(LL i=1;i<=n;i++) if(!ind[i]) q[tl++]=i;
	while(hd<tl){
		LL x=q[hd++]; p[x]=++cnt;
		for(LL i=fs[x];i!=-1;i=nt[i]) if(!(--ind[to[i]])) q[tl++]=to[i];
	}
	F[0]=1;
	for(LL i=0;i<n;i++){
		LL minn=n+2;
		for(LL j=i+1;j<=n;j++){
			if(p[j]>minn||p[j]<p[i]) continue;
			F[j]+=F[i],minn=p[j];
		}
	}
	for(LL i=n,maxn=0;i;i--) if(p[i]>maxn) ans+=F[i],maxn=p[i];
	printf("%lld\n",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/OYJason/p/9744776.html

时间: 2024-10-13 05:30:54

CodeForces Gym 100228 Graph of Inversions的相关文章

[Gym 100228] Graph of Inversions

题意 给定长度为 $n$ 的序列 $A = \left\{ a_1, a_2, ..., a_n \right\}$ . 我们定义其逆序图 $G$ : 对于 $i < j$ , $i, j$ 之间存在连边 $\Leftrightarrow a_i > a_j$ . 给定一个序列的逆序图, 求有多少个点集 $S$ , 满足 $S$ 既是独立集, 又是覆盖集. $n \le 1000$ . 分析 我们考虑探究逆序图与原序列的关系. 点集 $S$ 在逆序图中是独立集, 当且仅当在原序列中单调不降.

【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,

Codeforces gym Hello 2015 Div1 B and Div2 D

Codeforces gym 100571 problem D Problem 给一个有向图G<V,E>和源点S,边的属性有长度L和颜色C,即E=<L,C>.进行Q次询问,每次给定一个点X,输出S到X的最短路的长度(不存在则输出 -1).但要求S到X的路径中相邻两条边颜色不一样. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 |V|, |E|: [1, 10^5] X, S: [1, |V| ] L: [1, 10^9] |C|

CodeForces 21D Traveling Graph 状压dp+欧拉回路

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 求从1点开始经过每条边至少一次最后回到1点的最小路程 显然就是找一条路径可重复的欧拉回路 思路: 首先对于欧拉回路的结论是:所有点的度数都为偶数 因为所有边至少经过一次,那么可以把题意转换成加最少多少条边使得图满足以上结论 而加的边目的是为了把奇度数转成偶度数,先floyd一下得到任意点间加边的最小花费 dp[i]表示状态i下度数都为偶数的最小花费. 状压dp,把i状态下,所有未选择的点中挑2个奇度数的转移即可. #include <cs

Codeforces gym Hello 2015 Div1 E

Codeforces gym 100570 problem E (一种处理动态最长回文子串问题的方法) Problem 给一个长度为N的字符串S,字符集是'a'-'z'.进行Q次操作,操作分三种.一,修改位置X的字符为C:二,查询以P位置为中心的最长回文子串的长度,并输出:三,查询以P与P+1的中间位置为中心的最长回文子串的长度,并输出. More 第二种操作子串长度为奇数,一定存在:第三种操作子串长度为偶数,若不存在,输出 -1. Limits Time Limit(ms): 4000(1s足

Codeforces gym Hello 2015 Div1 C and Div2 E

Codeforces gym 100570 problem C Codeforces gym 100571 problem E Problem 给一个N行M列的矩阵Ma,进行Q次(Q<=10)查询,每次给定一个K,问有多少子矩阵,满足最大值max - 最小值min <=K. Limits Time Limit(ms): 8000 Memory Limit(MB): 512 N, M: [1, 400] Q: [1, 10] Ma(i, j), K: [1, 10^9] Solution (Th

【模拟】ECNA 2015 I What&#39;s on the Grille? (Codeforces GYM 100825)

题目链接: http://codeforces.com/gym/100825 题目大意: 栅栏密码.给定N(N<=10),密钥为一个N*N的矩阵,'.'代表空格可以看到,'X'代表被遮挡,还有密文字符串S,长度为N*N 每次将这个矩阵顺时针旋转90°,把矩阵中空格对应的位置按照从上到下从左到右的顺序依次填充上密文字符,求最终这个密文字符能否填满N*N的矩阵,能按顺序输出得到的答案,不能输出"invalid grille" 题目思路: [模拟] 直接模拟即可.旋转的坐标公式很好推.

Codeforces 466E Information Graph(dfs+并查集)

题目链接:Codeforces 466E Information Graph 题目大意:一开始有n个员工,他们互相独立.现在有三种操作. 1 u v,v称为u的上级 2 u,从u发起一份文件,逐层递交给上级 3 u v,询问u是否查阅过v号文件. 解题思路:将每个文件移动的范围处理出来,然后对于每次询问,将询问拆成两个标记,假设查询x是否浏览过第k号文件,第k号文件的范围为u-v,那么在最后dfs时,遍历到x,判断是否经过u:遍历到v时,判断是否经过x.如果两个都满足,则是YES. #inclu

Codeforces gym Hello 2015 Div2 B

Codeforces gym 100571 problem B Problem 设函数F(x),F(1)与F(2)已知,且当 i>=3,F(i)=a*F(i-2)+b*F(i-1).再给一个长度为N的数列A,进行Q次如下操作:每次给一个区间[L, R],对于每个k(L=<k<=R),将A[k]=A[k]+F[k-L+1].最后输出数列A(mod 10^9+7). Limits Time Limit(ms): 1000 Memory Limit(MB): 256 N, Q: [1, 10^