【題解】[AGC028D] Chords

[AGC028D] Chords

\(\text{Solution:}\)

首先要觀察到,如果把連通塊的最小點和最大點連起來,那麼每個連通塊之間必然不相交。

所以我們考慮計算當 \(l,r\) 在同一個連通塊的時候有多少種情況,最後就是枚舉所有對然後加起來。由於 \(l,r\) 一個最大一個小,所以不會算重。

\(f[l,r]\) 表示 \([l,r]\) 作爲連通塊端點的方案數。容易發現,首先不能讓區間中的點連到外邊。

其次,發現這個東西不好算,於是考慮一個容斥。先不考慮外部情況,要算內部的使得 \([l,r]\) 連通的情況,首先可以讓它們隨便連,再去枚舉從哪裏開始出現了新的連通塊使得它們斷開。從左往右枚舉分界線,左端是 \(f[l,k],\) 右端就是任意連的方案數,用整體任意連接的方案數減去容斥的這一部分就是答案。

值得注意的一點是,不能讓外部的係數統計到 \(f\) 裏面,否則會導致轉移的時候所乘的 \(f\) 都帶上了一個組合的係數,而這個係數不是轉移到的狀態想要的係數。

複雜度 \(O(n^3)\)

#include <bits/stdc++.h>
using namespace std;
typedef double db;
#define int long long
#define fi first
#define se second
#define mk make_pair
#define pb emplace_back
#define poly vector<int>
#define Bt(a) bitset<a>
#define bc __builtin_popcount
#define pc putchar
#define ci const int&
const int mod = 1e9 + 7;
const db eps = 1e-10;
const int inf = (1 << 30);
inline int Max(ci x, ci y) {return x > y ? x : y;}
inline int Min(ci x, ci y) {return x < y ? x : y;}
inline db Max(db x, db y) {return x - y > eps ? x : y;}
inline db Min(db x, db y) {return x - y < eps ? x : y;}
inline int Add(ci x, ci y, ci M = mod) {return (x + y) % M;}
inline int Mul(ci x, ci y, ci M = mod) {return 1ll * x * y % M;}
inline int Dec(ci x, ci y, ci M = mod) {return (x - y + M) % M;}
typedef pair<int, int> pii;
inline int Abs(int x) {return x < 0 ? -x : x;}
//char buf[1<<21],*p1=buf,*p2=buf;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char Obuf[105000],*O=Obuf;//Siz shoule be the size of Out File
int pst[30],ptop;
inline void Fprint(){fwrite(Obuf,1,O-Obuf,stdout);}
inline void Fwrite(int x){
  if(x==0){*O++='0';return;}
  if(x<0)*O++='-',x=-x;ptop=0;
  while(x)pst[++ptop]=x%10,x/=10;
  while(ptop)*O++=pst[ptop--]+'0';
  if(O-Obuf>100000)Fprint(),O=Obuf;
}
inline int read() {
    int s = 0, w = 1;
    char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') w = -1;ch = getchar();}
    while (isdigit(ch)) {s = s * 10 + ch - '0';ch = getchar();}
    return s * w;
}
inline void write(int x) {
    if (x < 0)putchar('-'), x = -x;
    if (x > 9)write(x / 10);
	pc(x % 10 + '0');
}
inline int qpow(int x, int y) {
    int res = 1;
    while (y) {if (y & 1)res = Mul(res, x);x = Mul(x, x);y >>= 1;}
    return res;
}
inline void cadd(int &x, int y) {x += y;}
inline void cmul(int &x, int y) {x *= y;}
inline void cmax(int &x, int y) {x = Max(x, y);}
inline void cmin(int &x, int y) {x = Min(x, y);}
const int N = 2e5 + 10;
namespace Refined_heart{
	int n,m,to[N],cl[N];
	int f[1000][1000];
	void solve(){
		n=read();m=read();
		for(int i=1;i<=m;++i){
			int u=read();int v=read();
			to[u]=v;to[v]=u;
		}
		cl[0]=1;
		for(int i=2;i<=5000;i+=2)cl[i]=Mul(cl[i-2],i-1);
		n<<=1;
		int ans=0;
		for(int i=1;i<=n;++i){
			for(int j=i+1;j<=n;++j){
				if((j-i+1)&1)continue;
				int len=j-i+1;
				int fg=0;
				for(int k=i;k<=j;++k){
					int v=to[k];
					if(!v)continue;
					if(v<i||v>j){
						fg=1;
						break;
					}
					len--;
				}
				if(fg)continue;
				int rest=n-(m<<1)-len;
				f[i][j]=cl[len];
				int cnt=0;
				for(int k=j;k>i;--k){
					if(!to[k])++cnt;
					f[i][j]=Dec(f[i][j],Mul(1,Mul(cl[cnt],f[i][k-1])));
				}
				ans=Add(ans,Mul(f[i][j],cl[rest]));
			}
		}
		write(ans);
	}
}
signed main(){
// 	freopen("in.txt","r",stdin);
//	freopen("My.out","w",stdout); 
	Refined_heart::solve();
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章