题解 Fiend

传送门

让求的这个东西是什么呢?
考虑矩阵 \(A_{i, j}=[l_i\leqslant j\leqslant r_i]\)
这个矩阵的行列式为

\[\det=\sum\limits_p(-1)^k\prod p_i \]

发现可以用这个东西的符号(以及是不是 0)来判断答案
那么要快速求这个矩阵的行列式
发现每一行中都有连续的一个区间是 1
考虑从小到大枚举 \(l\),在左端点是 \(l\) 的所有行中取 \(r\) 最小的,将其他行都消成 \([r+1, \cdots]\)
这样每一行都是一个连续的区间
这个过程需要可并堆,众所周知,最好写的左偏树是 pb_ds 左偏树
消完后每行都只剩下一个数,唯一对应了一个排列,直接计算逆序对数即可
那么复杂度 \(O(n\log n)\)

点击查看代码
#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define ll long long
//#define int long long

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++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int a[N], l[N], r[N];

namespace force{
	int ans1, ans2;
	void solve() {
		ans1=ans2=0;
		for (int i=1; i<=n; ++i) a[i]=i;
		int cnt;
		do {
			for (int i=1; i<=n; ++i) if (a[i]<l[i]||a[i]>r[i]) goto jump;
			cnt=0;
			for (int i=1; i<=n; ++i)
				for (int j=i+1; j<=n; ++j)
					if (a[i]>a[j]) ++cnt;
			++(cnt&1?ans1:ans2);
			jump: ;
		} while (next_permutation(a+1, a+n+1));
		if (ans2>ans1) puts("Y");
		else if (ans2<ans1) puts("F");
		else puts("D");
	}
}

namespace task1{
	pair<ll, ll> f[1<<15];
	void solve() {
		memset(f, 0, sizeof(f));
		f[0]={1, 0};
		int lim=1<<n;
		for (int s=0,pos; s<lim; ++s) {
			pos=__builtin_popcount(s)+1;
			for (int i=0; i<n; ++i) if (!(s&(1<<i)) && l[pos]<=i+1 && i+1<=r[pos]) {
				int cnt=__builtin_popcount(s>>i);
				if (cnt&1) f[s|(1<<i)].fir+=f[s].sec, f[s|(1<<i)].sec+=f[s].fir;
				else f[s|(1<<i)].fir+=f[s].fir, f[s|(1<<i)].sec+=f[s].sec;
			}
		}
		if (f[lim-1].fir>f[lim-1].sec) puts("Y");
		else if (f[lim-1].fir<f[lim-1].sec) puts("F");
		else puts("D");
	}
}

namespace task{
	int bit[N], p[N], ans;
	inline void add(int i) {for (; i; i-=i&-i) ++bit[i];}
	inline int query(int i) {int ans=0; for (; i<=n; i+=i&-i) ans+=bit[i]; return ans;}
	struct cmp{inline bool operator () (pair<int, int> a, pair<int, int> b){return a>b;}};
	__gnu_pbds::priority_queue<pair<int, int>, cmp, pairing_heap_tag> q[N];
	void solve() {
		ans=1;
		memset(bit, 0, sizeof(bit));
		for (int i=1; i<=n; ++i) q[i].clear();
		for (int i=1; i<=n; ++i) q[l[i]].push({r[i], i});
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			if (!q[i].size()) {ans=0; break;}
			int r=q[i].top().fir;
			// cout<<"lr: "<<i<<' '<<r<<endl;
			p[q[i].top().sec]=i;
			q[i].pop();
			if (q[i].size() && q[i].top().fir==r) ans=0;
			q[r+1].join(q[i]);
		}
		for (int i=1; i<=n&&ans; ++i) ans*=(query(p[i])&1?-1:1), add(p[i]);
		if (!ans) puts("D");
		else if (ans>0) puts("Y");
		else puts("F");
	}
}

signed main()
{
	freopen("fiend.in", "r", stdin);
	freopen("fiend.out", "w", stdout);

	int T=read();
	while (T--) {
		n=read();
		for (int i=1; i<=n; ++i) l[i]=read(), r[i]=read();
		// force::solve();
		task::solve();
	}

	return 0;
}
posted @ 2022-04-06 19:55  Administrator-09  阅读(2)  评论(0编辑  收藏  举报