首页 > 其他分享 >AtCoder Grand Contest 023 E Inversions

AtCoder Grand Contest 023 E Inversions

时间:2023-09-20 10:23:36浏览次数:31  
标签:AtCoder frac limits Contest times Inversions prod define

洛谷传送门

AtCoder 传送门

首先将 \(a\) 从小到大排序,设 \(p_i\) 为排序后的 \(a_i\) 位于原序列第 \(p_i\) 个位置,\(x_i\) 为要填的排列的第 \(i\) 个数。

设 \(A = \prod\limits_{i = 1}^n (a_i - i + 1)\),则 \(A\) 为排列的总方案数(考虑按 \(a_i\) 从小到大填即得)。

套路地,统计每对 \((i, j), i < j\) 造成的逆序对贡献。设 \(f(i, j)\) 为 \((p_i, p_j)\) 在排列中构成逆序对的方案。

若 \(p_i < p_j\),则 \(x_i > x_j\) 有:

\[\begin{aligned}f(i, j) & = \frac{(a_i - i + 1)(a_i - i)}{2} \times \frac{A}{(a_i - i + 1)(a_j - j + 1)} \times \prod\limits_{k = i + 1}^{j - 1} \frac{a_k - k}{a_k - k + 1} \\ & = \frac{(a_i - i)A}{2(a_j - j + 1)} \times \prod\limits_{k = i + 1}^{j - 1} \frac{a_k - k}{a_k - k + 1}\end{aligned} \]

考虑在 \([1, a_i]\) 中选出两个数分配给 \(x_i\) 和 \(x_j\),在总方案数中去除 \(x_i, x_j\) 造成的贡献,对于 \(k \in [i + 1, j - 1]\),\(x_k\) 能选的数少了 \(1\) 个,故减去。然后约分化简得上式。

若 \(p_i > p_j\),我们计算 \((i, j)\) 构成顺序对的方案数再减去,有:

\[f'(i, j) = A - \frac{(a_i - i)A}{2(a_j - j + 1)} \times \prod\limits_{k = i + 1}^{j - 1} \frac{a_k - k}{a_k - k + 1} \]

看到式子有个 product 很不顺眼,考虑设 \(b_i = \prod\limits_{j = 1}^i \frac{a_j - j}{a_j - j + 1}\),\(c_i = \frac{1}{b_i} = \prod\limits_{j = 1}^i \frac{a_j - j + 1}{a_j - j}\)。那么:

\[f(i, j) = A \times ((a_i - i) \times c_i) \times \frac{b_{j - 1}}{a_j - j + 1} \]

这是一个二维偏序的形式(\(i < j \land p_i < p_j\))。树状数组维护 \((a_i - i) \times c_i\) 的和,在 \(j\) 处乘上 \(\frac{b_{j - 1}}{a_j - j + 1}\) 并加入最终答案即可。

对于 \(f'(i, j)\),我们还需要计算 \(i < j \land p_i > p_j\) 的数量,可以再开一个树状数组。

但是这样有个问题,可能存在 \(a_i - i = 0\),因此可能存在 \(b_i = 0\)。为了不影响前缀积,考虑强制把 \(a_i - i = 0\) 的位置当作 \(1\) 乘进去,然后规定计算 \(f(i, j)\) 时,若 \(\exists k \in [i + 1, j - 1], a_k - k = 0\),就使 \(f(i, j) = 0\)。那我们可以把 \(a_k - k = 0\) 的位置看作一个挡板,把序列分成若干个块,每次只计算块内互相贡献的答案即可。

目前是 AtCoder 最优解。

code
// Problem: E - Inversions
// Contest: AtCoder - AtCoder Grand Contest 023
// URL: https://atcoder.jp/contests/agc023/tasks/agc023_e
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline int read() {
    char c = getchar();
    int x = 0;
    for (; !isdigit(c); c = getchar()) ;
    for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x;
}

const int maxn = 200100;
const ll mod = 1000000007;
const ll inv2 = (mod + 1) / 2;

ll n, inv[maxn], b[maxn], c[maxn], d[maxn], f[maxn], g[maxn];

struct node {
	ll x, i;
} a[maxn];

inline void upd(ll &x, ll y) {
	((x += y) >= mod) && (x -= mod);
}

struct BIT {
	ll c[maxn];
	
	inline void update(int x, ll d) {
		for (int i = x; i <= n; i += (i & (-i))) {
			upd(c[i], d);
		}
	}
	
	inline ll query(int x) {
		ll res = 0;
		for (int i = x; i; i -= (i & (-i))) {
			upd(res, c[i]);
		}
		return res;
	}
	
	inline ll query(int l, int r) {
		return (query(r) - query(l - 1) + mod) % mod;
	}
} t1, t2;

void solve() {
	n = read();
	inv[0] = inv[1] = 1;
	for (int i = 2; i <= n; ++i) {
		inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	}
	for (int i = 1; i <= n; ++i) {
		a[i].x = read();
		a[i].i = i;
	}
	sort(a + 1, a + n + 1, [&](const node &a, const node &b) {
		return a.x < b.x;
	});
	ll A = 1;
	for (int i = 1; i <= n; ++i) {
		A = A * (a[i].x - i + 1) % mod;
	}
	if (!A) {
		puts("0");
		return;
	}
	ll B = A * inv2 % mod;
	b[0] = c[0] = 1;
	for (int i = 1; i <= n; ++i) {
		b[i] = b[i - 1] * max(a[i].x - i, 1LL) % mod * inv[a[i].x - i + 1] % mod;
		c[i] = c[i - 1] * inv[a[i].x - i] % mod * (a[i].x - i + 1) % mod;
		f[i] = b[i - 1] * inv[a[i].x - i + 1] % mod;
		g[i] = (a[i].x - i) * c[i] % mod;
	}
	ll ans = 0;
	for (int i = 1, j = 1; i <= n; ++i) {
		ans = (ans + B * t1.query(a[i].i - 1) % mod * f[i] % mod) % mod;
		ll res = B * t1.query(a[i].i + 1, n) % mod * f[i] % mod;
		ans = (ans + A * t2.query(a[i].i + 1, n) % mod - res + mod) % mod;
		t1.update(a[i].i, g[i]);
		t2.update(a[i].i, 1);
		if (a[i].x == i) {
			while (j < i) {
				t1.update(a[j].i, mod - g[j]);
				++j;
			}
		}
	}
	printf("%lld\n", ans);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:AtCoder,frac,limits,Contest,times,Inversions,prod,define
From: https://www.cnblogs.com/zltzlt-blog/p/17716618.html

相关文章

  • 2018-2019 ACM-ICPC Brazil Subregional Programming Contest
    \(B.Marbles\)如果是\(Nim\)博弈,题目应该改成到转移所有石子。显然要转化到将所有石子转移到\((1,2)\)或者\((2,1)\),特判无需到达这两个点的必败态,对其他点使用\(Nim\)博弈判断胜负态。intsg[N][N],vis[N];voidinit(){for(inti=1;i<=100;i++){for(in......
  • Atcoder Regular Contest 165(A~E)
    赛时45min切A~C,降智不会D,罚坐1h,喜提rk70+->rk170+。A-SumequalsLCM可证明结论:若\(N\)只含有一种质因子则无解,否则有解。B-SlidingWindowSort2这么多cornercase的题竟然10min一发入魂,类目了。由于操作是升序排序,且要求最终字典序最大,所以如果存在一个......
  • AtCoder Beginner Contest 320
    A-LeylandNumbera,b=map(int,input().split(''))print(a**b+b**a)B-LongestPalindromes=input()n=len(s)res=0forlinrange(1,n+1):foriinrange(0,n-l):t=q=s[i:i+l]t=t+t[::-1]......
  • The 2023 ICPC Asia Regionals Online Contest (1) ADI
    The2023ICPCAsiaRegionalsOnlineContest(1)AQualifiersRankingRules思路:按位次为第一关键字,场次为第二关键字排序即可。//AConemoretimes//nndbk#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintmod=1e9+7;constintN......
  • [ARC119F] AtCoder Express 3
    题目链接观察样例1的解释,发现切换类型的方法是比较单一的这种就是直接走一段换一段,我们可以人为钦定换乘时最多走一步,因为相邻的同色也可以视作走车站这种情况复杂一些,需要往回走一段,但是依然可以发现往回走也至多一步,因为如果走了两步说明往回走了一步到达的车站依......
  • 【杂题乱写】AtCoder-ARC113
    AtCoder-ARC113AA*B*C枚举\(A,B\),那么\(C\in[1,\left\lfloor\frac{K}{AB}\right\rfloor]\),时间复杂度是\(O(K\logK)\)。提交记录:Submission-AtCoderAtCoder-ARC113BA^B^C\(A^k\)的末尾存在循环节,找到循环节长度\(|T|\),答案就是\(A^{B^C\bmod|T|}\bmod10\)。提......
  • 【题解】AtCoder-ABC320
    AtCoder-ABC320ALeylandNumber依题意计算。提交记录:Submission-AtCoderAtCoder-ABC320BLongestPalindrome直接\(O(n^2)\)枚举,\(O(n)\)判断。提交记录:Submission-AtCoderAtCoder-ABC320CSlotStrategy2(Easy)不妨将字符串复制三遍,枚举\([0,3m)\)判断。提交......
  • 2018-2019 ACM-ICPC Brazil Subregional Programming Contest
    B.Marbles题解显然如果存在棋子位于\((x,x)\),那么一定先手必胜容易发现必败态位于\((1,2)\)和\((2,1)\),那么我们可以通过\(sg\)函数暴力打表得到并且玩家一定不会将棋子移动至\((0,i),(i,0),(i,i)\)这三种情况上,因为谁移动到这些位置,对手一定处于必胜态intn,f[N][......
  • atcoder313C
    313C题目概述:给定序列A,可以任选两个数,使其中一个数加1,另一个数减1.可以通过任意次操作,问需要至少多少次操作,才能使A中最大数和最小数差值不超过1。解题思路:将该题进行抽象转化:1.我们需要将A序列转化为B序列,sumB=sumA。操作次数为:\(\frac{\sum\limits_{i}^n|a_i-b_i|}{2}\)2......
  • 2020-2021 ACM-ICPC Brazil Subregional Programming Contest
    A.StickerAlbum你想要得到\(n\)张贴纸,每包礼物中等概率出现\([A,B]\)范围内数量的贴纸,求需要买多少包礼物才能至少获得\(n\)张贴纸的期望次数\(1\leqn\leq10^6,0\leqA,B\leq10^6\)题解:期望DP我们考虑从后往前进行\(dp\)设计状态为\(dp[i]\)代表手上有\(i\)张......