若是\(N = M\)node
答案是\(2N!M!\)c++
若是\(|N - M| = 1\)ui
答案是\(N!M!\)spa
不然答案是0code
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define space putchar(' ') #define enter putchar('\n') #define eps 1e-10 #define MAXN 100005 //#define ivorysi using namespace std; typedef long long int64; typedef unsigned int u32; typedef double db; template<class T> void read(T &res) { res = 0;T f = 1;char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 +c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } const int MOD = 1000000007; int N,M; int fac[MAXN]; int inc(int a,int b) { return a + b >= MOD ? a + b - MOD : a + b; } int mul(int a,int b) { return 1LL * a * b % MOD; } void Solve() { read(N);read(M); if(abs(N - M) > 1) {puts("0");return;} fac[0] = 1; for(int i = 1 ; i <= max(N,M) ; ++i) { fac[i] = mul(fac[i - 1],i); } int ans = mul(fac[N],fac[M]); if(N == M) { ans = mul(ans,2); } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }
发现横坐标排序和纵坐标排序后,只有相邻的边会有边排序
而后跑最小生成树便可ci
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define space putchar(' ') #define enter putchar('\n') #define eps 1e-10 #define MAXN 100005 //#define ivorysi using namespace std; typedef long long int64; typedef unsigned int u32; typedef double db; template<class T> void read(T &res) { res = 0;T f = 1;char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 +c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } const int MOD = 1000000007; int N; int x[MAXN],y[MAXN]; int id[MAXN],cnt,fa[MAXN]; struct node { int u,v,c; }E[MAXN * 10]; int getfa(int u) { return fa[u] == u ? u : fa[u] = getfa(fa[u]); } void Solve() { read(N); for(int i = 1 ; i <= N ; ++i) {read(x[i]);read(y[i]);} for(int i = 1 ; i <= N ; ++i) id[i] = i; sort(id + 1,id + N + 1,[](int a,int b) {return x[a] < x[b];}); for(int i = 1 ; i < N ; ++i) { E[++cnt] = (node){id[i],id[i + 1],x[id[i + 1]] - x[id[i]]}; } for(int i = 1 ; i <= N ; ++i) id[i] = i; sort(id + 1,id + N + 1,[](int a,int b) {return y[a] < y[b];}); for(int i = 1 ; i < N ; ++i) { E[++cnt] = (node){id[i],id[i + 1],y[id[i + 1]] - y[id[i]]}; } sort(E + 1,E + cnt + 1,[](node a,node b){return a.c < b.c;}); for(int i = 1 ; i <= N ; ++i) fa[i] = i; int ans = 0; for(int i = 1 ; i <= cnt ; ++i) { if(getfa(E[i].u) != getfa(E[i].v)) { ans += E[i].c; fa[getfa(E[i].u)] = getfa(E[i].v); } } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }
只有两个点都在边上的连线才有影响,咱们把这些点按照顺时针(逆时针也能够)扔进栈里,栈顶元素和它相同则弹出,若是最后栈是空的就合法,不然就不合法get
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define space putchar(' ') #define enter putchar('\n') #define eps 1e-10 #define MAXN 100005 //#define ivorysi using namespace std; typedef long long int64; typedef unsigned int u32; typedef double db; template<class T> void read(T &res) { res = 0;T f = 1;char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 +c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } struct node { int x,y,p; }; int R,C; int N; int x[MAXN][2],y[MAXN][2]; vector<node> v[4]; int sta[MAXN * 2],top; bool on_u(int x,int y) { return x == 0; } bool on_l(int x,int y) { return x != 0 && x != R && y == 0; } bool on_r(int x,int y) { return x != 0 && x != R && y == C; } bool on_d(int x,int y) { return x == R; } bool check(int x,int y) { return on_u(x,y) || on_l(x,y) || on_r(x,y) || on_d(x,y); } int id(int x,int y) { if(on_u(x,y)) return 0; else if(on_r(x,y)) return 1; else if(on_d(x,y)) return 2; else return 3; } void Solve() { read(R);read(C);read(N); for(int i = 1 ; i <= N ; ++i) { for(int j = 0 ; j <= 1 ; ++j) {read(x[i][j]);read(y[i][j]);} if(check(x[i][0],y[i][0]) && check(x[i][1],y[i][1])) { v[id(x[i][0],y[i][0])].pb((node){x[i][0],y[i][0],i}); v[id(x[i][1],y[i][1])].pb((node){x[i][1],y[i][1],i}); } } sort(v[0].begin(),v[0].end(),[](node a,node b){return a.y < b.y;}); sort(v[1].begin(),v[1].end(),[](node a,node b){return a.x < b.x;}); sort(v[2].begin(),v[2].end(),[](node a,node b){return a.y > b.y;}); sort(v[3].begin(),v[3].end(),[](node a,node b){return a.x > b.x;}); for(int i = 0 ; i < 4 ; ++i) { for(auto t : v[i]) { if(sta[top] == t.p) --top; else sta[++top] = t.p; } } if(top) puts("NO"); else puts("YES"); } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }
线段树维护hall定理,好像以前遇到过相似的可是没有写这个作法。。。it
hall定理是什么呢class
\(X,Y\)为两边的点集,\(X\)和\(Y\)之间存在完美匹配,仅当\(X\)中任意\(k\)个点组成的点集和\(Y\)中的至少$k
$个点相连
这是充分必要的
那么咱们求的是人数-最大匹配,也就是每一个点集减去匹配\(Y\)点集椅子个数的最大值,初始的答案先设成\(max(N - M,0)\)
设点集大小为\(|X|\),匹配\(Y\)点集的椅子数是\(\Gamma(X)\)
答案显然不小于\((|X| - |\Gamma(X)|)_{max}\)
若是答案大于\((|X| - |\Gamma(X)|)_{max}\),设\(t > (|X| - |\Gamma(X)|)_{max}\),若是当前存在一个大于t的未匹配点,那么选这t个点必定与对面至少一个点相连,设为\(v\),若v被匹配,找到匹配点u,u与这t个点组成的点集匹配至少两个点,因此能够增长一个匹配点,能够证实答案不大于\((|X| - |\Gamma(X)|)_{max}\)
因此只要考虑怎么求\((|X| - |\Gamma(X)|)_{max}\)
显然是对于一个固定的区间,计算多少个点的\(L_{i},R_{i}\)覆盖了这个区间,因此把区间按左端点排序,而后线段树维护便可
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define space putchar(' ') #define enter putchar('\n') #define eps 1e-10 #define MAXN 200005 //#define ivorysi using namespace std; typedef long long int64; typedef unsigned int u32; typedef double db; template<class T> void read(T &res) { res = 0;T f = 1;char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 +c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int N,M; struct node { int l,r; }p[MAXN]; struct seg_tree { int l,r; int lz,mx; }tr[MAXN * 4]; void update(int u) { tr[u].mx = max(tr[u << 1 | 1].mx,tr[u << 1].mx); } void addlz(int u,int v) { tr[u].mx += v;tr[u].lz += v; } void pushdown(int u) { if(tr[u].lz) { addlz(u << 1,tr[u].lz); addlz(u << 1 | 1,tr[u].lz); tr[u].lz = 0; } } void build(int u,int l,int r) { tr[u].l = l;tr[u].r = r; if(l == r) { tr[u].mx = r; return; } int mid = (l + r) >> 1; build(u << 1,l,mid); build(u << 1 | 1,mid + 1,r); update(u); } void Change(int u,int l,int r,int v) { if(tr[u].l == l && tr[u].r == r) {addlz(u,v);return;} pushdown(u); int mid = (tr[u].l + tr[u].r) >> 1; if(r <= mid) Change(u << 1,l,r,v); else if(l > mid) Change(u << 1 | 1,l,r,v); else {Change(u << 1,l,mid,v);Change(u << 1 | 1,mid + 1,r,v);} update(u); } int Query(int u,int l,int r) { if(tr[u].l == l && tr[u].r == r) {return tr[u].mx;} pushdown(u); int mid = (tr[u].l + tr[u].r) >> 1; if(r <= mid) return Query(u << 1,l,r); else if(l > mid) return Query(u << 1 | 1,l,r); else return max(Query(u << 1,l,mid),Query(u << 1 | 1,mid + 1,r)); } void Solve() { read(N);read(M); for(int i = 1 ; i <= N ; ++i) { read(p[i].l);read(p[i].r); } build(1,1,M + 1); sort(p + 1,p + N + 1,[](node a,node b){return a.l < b.l || (a.l == b.l && a.r > b.r);}); int ans = max(0,N - M); for(int i = 1 ; i <= N ; ++i) { Change(1,p[i].l + 1,p[i].r,1); int t = Query(1,p[i].l + 1,M + 1) - M - p[i].l - 1; ans = max(ans,t); } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }