CF1542E2 Abnormal Permutation Pairs (hard version) 题解

怎么会有这么离谱的题目啊。

【模板】前缀和优化 dp。

思路#

考虑一个基本的东西。

由于要求字典序的限制。

我们可以枚举最长公共前缀计算。

考虑如何求长度为 i 的排列有 j 个逆序对的数量。

dpi,j

dpi,j=k=0i1dpi1,jk

就是枚举新的数放在那里。

不难看出可以前缀和优化。

dpi,j=gi1,jkgi1,ji

就可以 O(n3) 计算。

到这里都是比较简单的。

考虑如何算答案。

首先列出较为朴素的 dp

枚举最长公共前缀长度 i,第 i+1 位两个排列分别放 x,y,后面 ni1 位分别会有 s,t 个逆序对。

i=0n1(ni)i!x=1ny=x+1nis=0(ni+12)t=0(ni+12)[s+x1>t+y1]dpni1,s×dpni1,t

稍微整理一下。

i=0n1(ni)i!x=1ny=x+1nis=0(ni+12)t=0s+xy1dpni1,s×dpni1,t

i=0n1(ni)i!x=1ny=x+1nis=0(ni+12)dpni1,st=0s+xy1dpni1,t

发现又可以前缀和优化。

gi,j=k=0jdpi,j

i=0n1(ni)i!x=1ny=x+1nis=0(ni+12)dpni1,s×gni1,s+xy1

i=0n1(ni)i!s=0(ni+12)dpni1,sx=1ny=x+1nigni1,s+xy1

这个时候,我发现了后面只与 xy 有关,那么可以枚举 xy=j

i=0n1(ni)i!s=0(ni+12)dpni1,sj=1ni1(nij)×gni1,s+xy1

这个式子已经可以 O(n4) 算了,可以通关简单版本。

但如何把它优化成 O(n3),我确实没有想到,如果有大佬会,可以教教我。

然后就发现我们走了很没有前途的一步,我也在这里卡了很久。

那么我们不得不往回退一步。

i=0n1(ni)i!s=0(ni+12)dpni1,sx=1niy=x+1nigni1,s+xy1

我们考虑继续前缀和优化。

hi,j=k=0jgi,k

i=0n1(ni)i!s=0(ni+12)dpni1,sx=1nihni1,s2hni1,s+xn+i1

发现这玩意还可以前缀和优化。

i=0n1(ni)i!s=0(ni+12)dpni1,s((ni)×hni1,s2x=1nihni1,s+xn+i1)

fi,j=k=0jhi,k

l=s+in1,r=s2

i=0n1(ni)i!s=0(ni+12)dpni1,s((ni)×hni1,s2(fni1,rfni1,l1))

然后就做完了。

可能有一些边界情况需要来判断。

Code#

/**
 * @file 1542E1.cpp
 * @author mfeitveer
 * @date 2023-11-14
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#include <bits/stdc++.h>
using namespace std;

#define x first
#define y second
#define mp(x, y) make_pair(x, y)
#define fro(i, x, y) for(int i = (x);i <= (y);i++)
#define pre(i, x, y) for(int i = (x);i >= (y);i--)
#define dbg cerr << "Line " << __LINE__ << ": "
#define EVAL(x) #x " = " << (x)

typedef int64_t i64;
typedef uint32_t u32;
typedef uint64_t u64;
typedef __int128_t i128;
typedef __uint128_t u128;
typedef pair<int, int> PII;

bool ed;

const int N = 510;
const int M = 124760;

int n, m, mod, c[N][N], vis[N][N], g[M], h[M], f[M], dp[N][M];

inline int add(int x, int y)
	{ return x + y + (x + y >= mod ? -mod : 0); }
inline void init(int now)
{
	fro(j, 0, 124750) g[j] = dp[now][j];
	fro(j, 1, 124750) g[j] = add(g[j], g[j - 1]);
	fro(j, 0, 124750) h[j] = g[j];
	fro(j, 1, 124750) h[j] = add(h[j], h[j - 1]);
	fro(j, 0, 124750) f[j] = h[j];
	fro(j, 1, 124750) f[j] = add(f[j], f[j - 1]);
}
inline int C(int x, int y)
{
	if(x < y) return 0;
	if(y == 0 || x == y) return 1;
	if(vis[x][y]) return c[x][y]; vis[x][y] = 1;
	return c[x][y] = (C(x - 1, y - 1) + C(x - 1, y)) % mod;
}
inline int ask(int l, int r)
{
	if(l - 1 < 0) return g[r];
	return (g[r] - g[l - 1] + mod) % mod;
}
inline void init()
{
	dp[0][0] = 1;
	fro(i, 1, 500)
	{
		init(i - 1);
		fro(j, 0, 124750) dp[i][j] = ask(j - i + 1, j);
	}
}
inline void solve()
{
	i64 ans = 0, num = 1;
	fro(i, 0, n - 1)
	{
		i64 res = 0; init(n - i - 1);
			fro(s, 2, (n - i - 1) * (n - i - 2) / 2)
			{
				i64 res1 = 1ll * h[s - 2] * (n - i) % mod;
				int ls = s + i - n - 1;
				i64 res2 = f[s - 2] - (ls <= 0 ? 0 : f[ls - 1]);
				res2 = (res2 % mod + mod) % mod;
				(res += (res1 - res2 + mod) * dp[n - i - 1][s]) %= mod;
		}
		(ans += res * num) %= mod, num = num * (n - i) % mod;
	}
	cout << ans << endl;
}

bool st;

signed main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	double Mib = fabs((&ed-&st)/1048576.), Lim = 1024;
	assert(Mib<=Lim), cerr << " Memory: " << Mib << "\n";
	cin >> n >> mod;
	init(), solve();
	return 0;
}

作者:JiaY19

出处:https://www.cnblogs.com/JiaY19/p/17832696.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   JiaY19  阅读(10)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示