zoukankan      html  css  js  c++  java
  • JZOJ 2020.10.6 【NOIP2017提高A组模拟9.7】简单无向图

    简单无向图

    题目

    Description

    在这里插入图片描述

    Input

    在这里插入图片描述

    Output

    在这里插入图片描述

    Sample Input

    输入1:
    4
    2 1 1 2
    输入2:
    10
    2 2 2 2 1 1 2 1 1 2

    Sample Output

    输出1:
    2
    输出2:
    18012

    Data Constraint

    在这里插入图片描述

    题解

    题目大意

    给出(n)个点和每个的度数
    问有多少合法的简单无向图

    分析

    手模之后发现,每个联通块要么是链,要么是环
    而链的个数是(dfrac{t1}{2})(t1)表示1的个数,(t2)表示2的个数,下同)
    然后打表找规律
    发现只跟1的方案数
    (w[i]=w[i-2]+w[i-4]*(i-2)*(i-3))
    那么现在就可以只考虑2了
    (f[i][j])表示当前用了(i)个2,其中(j)个用作环,那么剩下(i-j)个就是用作链
    对于当前这一个
    有3种情况

    1. 新环。(f[i][j]+=f[i-3][j-3]*(i-1)*(i-2)/2)
    2. 进到一个环里。(f[i][j]+=f[i-1][j-1]*(j-1))
    3. 进到一个链里。(f[i][j]+=f[i-1][j]*(i-j-1+t1))

    解释

    • 要加入一个新的环,需要3个点。去掉当前这个点,还需要在i-1里选两个点,即(C_{i-1}^2),就是((i-1)*(i-2)/2)
    • 进到一个环里,现在一个环里有(j-1)个位置,那么这个点可以选任意一个位置来访
    • 进到一个链是一样的,总共有(i-j-1+t1)个位置可以放

    注意一下爆(int)的问题
    答案就是(w[t1]*sum_{i=0}^{t2}f[t2][i])

    总结

    这题的状态需要想一下
    式子有点难推
    需要提高对设状态的熟练度

    Code

    #include<bits/stdc++.h>
    #define mod 998244353
    using namespace std;
    long long n,x,t1,t2,ans,sum,one[2005],f[2005][2005];
    int read()
    {
    	int res=0;char ch=getchar();
    	while (ch<'0'||ch>'9') ch=getchar();
    	while (ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch-'0'),ch=getchar();
    	return res;
    }
    int main()
    {
    	freopen("graph.in","r",stdin);
    	freopen("graph.out","w",stdout);
    	n=read();
    	for (int i=1;i<=n;++i)
    	{
    		x=read();
    		if (x==1) ++t1;
    		else ++t2;
    	}
    	one[0]=1;
    	for (int i=2;i<=t1;++i)
    		one[i]=(one[i-2]+(long long)one[i-4]*(i-3)*(i-2)%mod)%mod;
    	ans=one[t1]%mod;
    	t1/=2;
    	f[0][0]=1;
    	for (long long i=1;i<=t2;++i)
    		for (long long j=0;j<=i;++j)
    		{
    			if (t1) f[i][j]=(long long)f[i-1][j]*(i-j-1+t1)%mod;
    			if (j>2) f[i][j]=(f[i][j]+(long long)(f[i-3][j-3]*(i-1)*(i-2)/2%mod))%mod;
    			if (j) f[i][j]=(f[i][j]+(long long)f[i-1][j-1]*(j-1)%mod)%mod;
    		}
    	for (int i=0;i<=t2;++i)
    		sum=(sum+f[t2][i])%mod;
    	printf("%lld
    ",ans*sum%mod);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    转载的一篇嵌入式大佬经验博文
    工程训练大赛心得体会
    Python之闭包与延时绑定问题
    python基础之装饰器
    python之内置函数(map,fillter,reduce)
    *arg和**kwarg作用
    C++之 ostream详细用法
    Linux 常用命令
    C++ 人脸识别系统的浅理解
    Linux 应用领域
  • 原文地址:https://www.cnblogs.com/Livingston/p/13774242.html
Copyright © 2011-2022 走看看