逆序对排列计数 & 行列式:1218T1
2023-12-18 18:21:04
http://47.92.197.167:5283/contest/439/problem/1
显然可以拆维,然后满足每一维是排列,然后逆序对奇偶会对答案有±1的贡献。然后分别算概率再乘起来。
接下来两个思考方向:
顺着思考
两个取值都在红色范围,显然可以交换,然后逆序对奇偶正好取反,贡献为0。因此就从左到右,强制钦定每个区间的取值必须是它自己独自占有的。
回到行列式形式
回到行列式形式,把所有左端点相同的找出来,拿右端点最小的去消元。然后最后行列式取值只能为0,1,-1(如果中途发现取不动了就说明行列式的值为0)
对于以上部分,我们直接拿可并堆或者启发式合并即可。
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//#define M
#define mo (int)(1e9+7)
#define N 100010
int pw(int a, int b) {
int ans=1;
while(b) {
if(b&1) ans*=a;
a*=a; b>>=1;
ans%=mo; a%=mo;
}
return ans;
}
void Mod(int &a) { if(a>=mo || a<=-mo) a%=mo; if(a<0) a+=mo; }
void Add(int &a, int b) { a+=b; Mod(a); }
void Mul(int &a, int b) { Mod(b); a*=b; Mod(a); }
struct Binary_tree {
int cnt[N];
void mem() { memset(cnt, 0, sizeof(cnt)); }
void add(int x) { while(x<N) cnt[x]++, x+=x&-x; }
int que(int x) {
int ans=0;
while(x) ans+=cnt[x], x-=x&-x;
return ans;
}
}Bin;
struct node {
int l, r;
}a1[N], a2[N];
int n, m, i, j, k, T, p[N], ans, sum;
struct Merge_tree {
int i, j, k, b[N];
#define par pair<int, int>
priority_queue<par, vector<par>, greater<par> >q[N];
// priority_queue<par>q[N];
#undef par
void init() { for(i=1; i<=n; ++i) b[i]=i; }
void add(int x, int i, int y) { q[b[x]].push({y, i}); }
void merge(int x, int y) {
// debug("Merging 1 ... \n");
int p = y; x = b[x]; y = b[y];
if(q[x].empty() && q[y].empty()) return ;
if(q[x].size() > q[y].size()) swap(x, y);
// debug("Merging 2 ... \n");
pair<int, int> t;
while(!q[x].empty()) t = q[x].top(), q[x].pop(), q[y].push(t);
debug("Merging 3 ... %d \n", q[y].size());
b[p]=y;
}
pair<int, int> query(int x) {
int p = x; x = b[x];
debug("query %d : %d\n", p, q[x].size());
if(q[x].empty()) return {-1, -1};
auto t = q[x].top(); q[x].pop();
if(p > t.fi) return {-1, -1};
return t;
}
};
int calc(node *a) {
Merge_tree Mer; Mer.init();
for(i=1; i<=n; ++i) Mer.add(a[i].l, i, a[i].r);
sum=1;
for(i=1; i<=n; ++i) Mul(sum, a[i].r-a[i].l+1);
debug("sum : %lld\n", sum);
for(i=1; i<=n; ++i) {
auto t = Mer.query(i);
if(t.fi == -1) return 0;
debug("Right Point : %lld\n", t.fi);
p[t.se] = i; Mer.merge(i, t.fi+1);
}
Bin.mem(); ans=0;
for(i=1; i<=n; ++i) ans+=Bin.que(p[i]), Bin.add(p[i]), debug("%lld ", ans); ;
debug("\n");
for(i=1; i<=n; ++i) debug("%lld ", p[i]); debug("\n");
debug("NXD : %lld\n", ans);
if(ans&1) ans=-1; else ans=1;
debug("ans : %lld\n", ans);
return ans * pw(sum, mo-2) % mo;
}
signed main()
{
freopen("math.in", "r", stdin);
freopen("math.out", "w", stdout);
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
// srand(time(NULL));
T=read();
while(T--) {
n=read();
for(i=1; i<=n; ++i) {
a1[i].l=read(); a1[i].r=read();
a2[i].l=read(); a2[i].r=read();
}
int s1 = calc(a1), s2 = calc(a2);
debug("%lld %lld\n", s1, s2);
ans = s1 * s2; Mod(ans);
printf("%lld\n", ans);
}
return 0;
}
文章来源:https://blog.csdn.net/zhangtingxiqwq/article/details/135065670
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!