zoukankan      html  css  js  c++  java
  • agc028D

    题目大意

    n<=300,k<=n

    题解

    网上的做法全是容斥,这里讲一种直接算的方法

    首先显然破环成链,因为如果两边相交则无论在哪里破都相交,不相交则都不相交

    那么一个连通块有其点范围[l,r],并且[l,r]内没有点跑到连通块外去

    现在直接枚举[l,r]来计数,计算min在l,max在r的极大连通块个数,并且其中可以包含小连通块(不交且不向外连边),然后乘上外面的情况求和即可

    因为现在只算大的,里面小的就作为独立的方案乘到大的里面,再乘上外面的就是当前连通块的总数

    设f[i,j]表示当前到i空点有j个,如果当前点是空的则可以连/不连,如果是边的左端点就在右端点时考虑,是右端点就接上唯一对应的左端点,如果超了左边界就break

    因为确定的边不能再当作空点,所以在枚举i时另外统计未匹配的左端点个数s

    考虑什么时候贡献答案,因为算的是极大连通块,所以要在其独立的瞬间计算,即内部空点j=0(不会往外连)且没有往后连的左端点(s=0)时,并且为了不让其继续往后影响要将其dp值设为0

    再处理出g[i]表示i个点的匹配方案即可,时间O(n^3)

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define add(a,b) a=((a)+(b))%mod
    #define mod 1000000007
    #define Mod 1000000005
    #define ll long long
    //#define file
    using namespace std;
    
    ll f[601][601],g[601][601],c[601],ans;
    int N,n,m,i,j,k,l,x,y,s;
    int a[601];
    
    ll qpower(ll a,int b) {ll ans=1; while (b) {if (b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;} return ans;}
    void init()
    {
    	g[1][1]=1;c[0]=1;
    	fo(i,2,N)
    	{
    		fo(j,0,n)
    		{
    			if (j<n) add(g[i][j+1],g[i-1][j]);
    			if (j>0) add(g[i][j-1],g[i-1][j]*j);
    		}
    		if (!(i&1)) c[i/2]=g[i][0];
    	}
    }
    
    int main()
    {
    	#ifdef file
    	freopen("agc028D.in","r",stdin);
    	#endif
    	
    	scanf("%d%d",&n,&m);N=n*2;
    	fo(i,1,m) scanf("%d%d",&x,&y),a[x]=y,a[y]=x;
    	init();
    	
    	fo(i,1,N)
    	{
    		memset(f,0,sizeof(f));
    		if (!a[i]) f[i][1]=1,l=0;
    		else
    		{
    			if (a[i]<i) continue;
    			f[i][0]=1,l=1;
    		}
    		s=0;
    		fo(j,i+1,N)
    		{
    			if (!a[j])
    			{
    				fo(k,0,n)
    				{
    					if (k<n) add(f[j][k+1],f[j-1][k]);
    					if (k>0) add(f[j][k-1],f[j-1][k]*k);
    				}
    				if (!l) add(ans,f[j][0]*c[n-(j-i+1)/2-(m-s)]),f[j][0]=0;
    			}
    			else
    			if (j<a[j])
    			{
    				fo(k,0,n)
    				add(f[j][k],f[j-1][k]);
    				++l;
    			}
    			else
    			{
    				if (a[j]<i) break;
    				--l;++s;
    				fo(k,0,n)
    				add(f[j][k],f[j-1][k]);
    				if (!l) add(ans,f[j][0]*c[n-(j-i+1)/2-(m-s)]),f[j][0]=0;
    			}
    		}
    	}
    	printf("%lld
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    Android开发探秘之一:创建可以点击的Button
    TCP之心跳包实现思路
    Asp.net与Dojo交互:仪器仪表实现
    Asp.net Json数据解析的一种思路
    Asp.net通过Jquery操作WebService进行Ajax读写
    GridView自定义删除操作
    从客户端中检测到有潜在危险的request.form值
    JUC-Condition线程通信
    ModelAndView 配置与使用
    SpringMVC之ModelAndView的用法(转)
  • 原文地址:https://www.cnblogs.com/gmh77/p/14012638.html
Copyright © 2011-2022 走看看