zoukankan      html  css  js  c++  java
  • BZOJ 4013 实验比较

    Description

    小D被邀请到实验室,做一个跟图片质量评价相关的主观实验。实验用到的图片集一共有(N)张图片,编号为(1)(N)。实验分若干轮进行,在每轮实验中,小(D)会被要求观看某两张随机选取的图片,然后小(D)需要根据他自己主观上的判断确定这两张图片谁好谁坏,或者这两张图片质量差不多。用符号“(<)”、“(>)”和“(=)”表示图片(x)(y)(x,y)为图片编号)之间的比较:如果上下文中(x)(y)是图片编号,则(x < y)表示图片(x)“质量优于”(y)(x > y)表示图片(x)“质量差于”(y)(x = y)表示图片(x)(y)“质量相同”;也就是说,这种上下文中,“(<)”、“(>)”、“(=)”分别是质量优于、质量差于、质量相同的意思;在其他上下文中,这三个符号分别是小于、大于、等于的含义。图片质量比较的推理规则(在(x)(y)是图片编号的上下文中):(1)(x < y)等价于(y > x)。(2)若(x < y)(y = z),则(x < z)。(3)若(x < y)(x = z),则(z < y)。(4)(x=y)等价于(y=x)。(5)若(x=y)(y=z),则(x=z)。 实验中,小 D 需要对一些图片对((x,y)),给出(x < y)(x = y)(x > y)的主观判断。小(D)在做完实验后, 忽然对这个基于局部比较的实验的一些全局性质产生了兴趣。在主观实验数据给定的情形下,定义这(N)张图片的一个合法质量序列为形如“(x_{1};R_{1};x_{2};R_{2};x_{3};R_{3} cdots x_{N-1};R_{N-1};x_{N})”的串,也可看作是集合(lbrace x_{i};R_{i};x_{i+1} mid 1 le i le N-1 brace),其中(x_{i})为图片编号,(x_{1},x_{2},cdots,x_{N})两两互不相同(即不存在重复编号),(R_{i})为<或=,“合法”是指这个图片质量序列与任何一对主观实验给出的判断不冲突。 由于实验已经做完一段时间了,小D已经忘了一部分主观实验的数据。对每张图片(i),小 D 都{最多只记住了某一张质量不比(i)差的另一张图片(K_{i})。这些小(D)仍然记得的质量判断一共有(M)((0 le M le N)),其中第(i)条涉及的图片对为((K_{X_{i}}, X_{i})),判断要么是(K_{X_{i}} < X_{i}),要么是(K_{X_{i}}=X_{i}),而且所有的(X_{i})互不相同。小D打算就以这(M)条自己还记得的质量判断作为他的所有主观数据。现在,基于这些主观数据,我们希望你帮小D求出这 (N)张图片一共有多少个不同的合法质量序列。我们规定:如果质量序列中出现“(x=y)”,那么序列中交换(x)(y)的位置后仍是同一个序列。因此: (1<2=3=4<5)(1<4=2=3<5)是同一个序列,(1 < 2 = 3)(1 < 3 = 2)是同一个序列,而(1 < 2 < 3)(1 < 2 = 3)是不同的序列,(1<2<3)(2<1<3)是不同的序列。由于合法的图片质量序列可能很多, 所以你需要输出答案对(10^{9}+7)取模的结果。

    Input

    第一行两个正整数(N,M),分别代表图片总数和小D仍然记得的判断的条数;
    接下来(M)行,每行一条判断,每条判断形如“(x < y)”或者”(x = y)”。

    Output

    输出仅一行,包含一个正整数,表示合法质量序列的数目对(10^{9}+7)取模的结果。

    Sample Input

    5 4
    1 < 2
    1 < 3
    2 < 4
    1 = 5

    Sample Output

    5

    Hint

    (N le 100)

    (=)缩掉之后如果该图没有环,那么一定是一棵森林结构,我们增添超级根,就变成了一颗树的结构了。
    如果(A,B)可以用(=)关系的话,那么(A,B)一定没有子树关系。所以,我们可以想到状态(f_{i,j})表示以(i)为根的子树,有(j)段((j-1)(<)的方案数)。利用辅助数组进行转移(g_{i,j,k})表示(i)的前(j)个儿子,分成了(k)段的方案数。那么我们就有转移$$g_{i,j,z} = sum C_{z}^{x} C_{x}^{x+y-z} g_{i,j-1,x} imes f_{son,y}(max(x,y) le z le x+y)$$
    其中(C_{z}^{x} C_{x}^{x+y-z})是转移系数,表示有(x)个白球,(y)个黑球,放进(z)个槽中,每个位置不能有两个颜色一样的球的方案数。

    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    
    typedef long long ll;
    #define rhl (1000000007)
    #define maxn (110)
    int father[maxn],side[maxn],next[maxn],toit[maxn],g[2][maxn][maxn];
    int tot,num,cnt,ind[maxn],C[maxn][maxn],f[maxn][maxn],ans,N,M;
    bool exist[maxn];
    struct node { int a,b; }edge[maxn];
    
    inline int find(int a) { if (father[a] != a) father[a] = find(father[a]); return father[a]; }
    inline void add(int a,int b)
    {
    	next[++cnt] = side[a]; side[a] = cnt;
    	toit[cnt] = b; ++ind[b]; exist[a] = exist[b] = true;
    }
    
    inline bool topsort()
    {
    	queue <int> team;
    	for (int i = 1;i <= N;++i) if (exist[i]&&!ind[i]) team.push(i),add(0,i);
    	int ret = 0;
    	while (!team.empty())
    	{
    		++ret; int now = team.front(); team.pop();
    		for (int i = side[now];i;i = next[i])
    			if (!--ind[toit[i]]) team.push(toit[i]);
    	}
    	return ret == num;
    }
    
    inline int dp(int now)
    {
    	int sz = 0,tmp,cur = 1;
    	g[0][now][0] = 1;
    	for (int i = side[now],v;i;i = next[i],cur ^= 1) 
    	{
    		tmp = dp(v = toit[i]);
    		for (int x = 0;x <= sz;++x)
    			for (int y = 1;y <= tmp;++y)
    				for (int z = max(x,y);z <= x+y;++z)
    				{
    					g[cur][now][z] += (ll)g[cur^1][now][x]*f[v][y]%rhl*(ll)C[z][x]%rhl*(ll)C[x][x+y-z]%rhl;
    					if (g[cur][now][z] >= rhl) g[cur][now][z] -= rhl;
    				}
    		memset(g[cur^1][now],0,sizeof(g[cur^1][now]));
    		sz += tmp;
    	}
    	for (int i = 0;i <= sz;++i) f[now][i+1] = g[cur^1][now][i];
    	return sz+1;
    }
    
    int main()
    {
    	freopen("4013.in","r",stdin);
    	freopen("4013.out","w",stdout);
    	scanf("%d %d",&N,&M); num = N;
    	for (int i = 1;i <= N;++i) father[i] = i;
    	for (int i = 1,a,b;i <= M;++i)
    	{
    		char c;
    		scanf("%d %c %d
    ",&a,&c,&b);
    		if (c == '<') edge[++tot] = (node){a,b};
    		else
    		{
    			int r1 = find(a),r2 = find(b);
    			if (r1 != r2) father[r1] = r2,--num;
    		}
    	}
    	for (int i = 1;i <= tot;++i) add(find(edge[i].a),find(edge[i].b));
    	if (!topsort()) printf("0");
    	else
    	{
    		C[0][0] = 1;
    		for (int i = 1;i <= N;++i)
    		{
    			C[i][0] = 1;
    			for (int j = 1;j <= i;++j)
    			{
    				C[i][j] = C[i-1][j] + C[i-1][j-1];
    				if (C[i][j] >= rhl) C[i][j] -= rhl;
    			}
    		}
    		int sz = dp(0);
    		for (int i = 1;i <= sz;++i) { ans += f[0][i]; if (ans >= rhl) ans -= rhl; }
    		printf("%d",ans);
    	}
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    linux tar order
    Linux驱动学习步骤(转载)
    汇编指令(转载)
    拓扑排序
    python 三维坐标图
    python 矩阵
    spring 之 IOC 依赖注入详解
    spring 下载
    Struts数据验证
    拦截器配置
  • 原文地址:https://www.cnblogs.com/mmlz/p/4448748.html
Copyright © 2011-2022 走看看