您的位置:首页 > 其它

【NOIP2017提高A组模拟9.7】简单无向图 dp

2017-09-16 09:33 459 查看
题目

题目大意

现在有一些度数为1,一些度数为2的点,求它们构成图的不同的方案数

tj

设有t1个度数为1的点,t2个度数为2的点,容易发现,答案只与t1,t2的数量有关,那么我们不妨设f[t1][t2]表示现在已经做了t1个1号点,t2个2号点的方案数

转移比较神奇,觉得出题人好**

分为下面的4种情况

1:当t2为0时我们新增若干条长度为2的链,我们将不会在这些链中间加其他任何点

2:新增形如1-2-1的一条新链

3:在条链的一个位置加入两个为2的点

4:把某一条链拆掉,将其中度数为2的点与3个新的点构成一个新的环

这个方法最关键的地方就是它是把一条链中间的度数为2的点和3个新的点构成一个环,很大程度上避免了在环中间加入新的数导致很难搞重复的窘境

贴代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define md 998244353
#define ll long long
using namespace std;

const int maxn=2005;

ll f[maxn][maxn];
ll i,j,k,l,m,n,x,y,t1,t2,cs1,cs2;

ll ge(ll x){
return ((x*(x-1))/2)%md;
}
int main(){
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%lld",&n);
fo(i,1,n){
scanf("%lld",&x);
if (x==1) cs1++; else cs2++;
}
f[0][0]=1;
fo(t2,0,cs2){
fo(t1,0,n){
if (f[t1][t2]==0) continue;
x=f[t1][t2];
if (t2==0) f[t1+2][t2]=(f[t1+2][t2]+x*(t1+1))%md;
f[t1+2][t2+1]=(f[t1+2][t2+1]+x*ge(t1+2))%md;
f[t1][t2+2]=(f[t1][t2+2]+((x*t1)%md)*(t2+1))%md;
if (t1>=2) f[t1-2][t2+3]=(f[t1-2][t2+3]+(x*ge(t2+2)))%md;
}
}
printf("%lld",f[cs1][cs2]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: