题意
构造长为 \(n\) 的序列 \(a\),满足 \(m\) 条限制:\(\min_{j=L_i}^{R_i}\{a_j\}=V_i\),要求逆序对数最少
题解
21pts 暴力
先进行一些观察:
- 逆序对只关心相对大小,所以 \(\forall a_j\) 必然 \(\in\{V_i\}\),可以完全离散化
- 经典结论:若 \(i<j,a_i>a_j\) 且交换后合法,则交换后更优
A
\(V_i=1\) 的限制等价于区间覆盖 \(1\);\(V_i=0\) 的限制等价于区间中存在 \(0\)
类似一个普及贪心题:按 \(L\) 从大到小考虑,区间中有 \(0\) 就跳过,没有就令第一个空位为 \(0\)(若第一个空位为 \(1\),则一定可以与区间中的 \(0\) 交换)
此时所有限制都满足了,剩下的位置可以随意填 \(0,1\),一定是前缀 \(0\) 后缀 \(1\),枚举分界点即可
B
相当于一些位置给定,其余位置随意
根据观察 2,空位是有序的,内部没有逆序对
一个自然的想法是单独考虑每个空位,令其与给定位置的逆序对数最少。事实上这样就能满足空位有序(反证,若有空位 \(i<j,a_i>a_j\),则“将 \(a_i\) 变成 \(a_j\)”和“将 \(a_j\) 变成 \(a_i\)”的增量互为相反数,一定有一个 \(\le0\))
也可以用决策单调性证明:
从前到后依次考虑每个空位,设 \(f[x]\) 表示当前位置填 \(x\) 与已经确定位置构成的逆序对数
空位会填 \(a_j=\text{argmin}\{f[x]\}\),令 \(f[1\sim a_j-1]+1\)
给定位置会令 \(f[1\sim a_j-1]+1,f[a_j+1\sim m]-1\),\(\text{argmin}\) 是单增的(若有 \(x<y,f[x]\ge f[y]\) 则修改后仍满足)
C
相当于限制是独立的
根据观察 2,每个限制一定是在 \(L_i\) 处填 \(V_i\)。问题转化为一些位置给定,其余位置满足 \(a_j\ge b_j\)
根据 B 猜测 \(a_j=\text{argmin}_{x\ge b_j}\{f[x]\}\)
证明类似。首先不论填什么都会使 \(f[1\sim b_j-1]+1\),其次现在 \(b_j\sim a_j-1\) 劣于 \(a_j\),之后一定不会变优,所以给 \(f[b_j\sim a_j-1]+1\) 没有影响
std
与 C 相比限制有重叠
\(V_i\) 大的可以替代掉小的。按 \(V_i\) 从大到小排序,同一 \(V_i\) 做 A,即可转化成 C
时间复杂度 \(O(n\log n)\),空间复杂度 \(O(n)\)
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std; using namespace __gnu_pbds; using namespace __gnu_cxx;
#define For(i,x,y,...) for(int i=x,##__VA_ARGS__;i<=(y);++i)
#define rFor(i,x,y,...) for(int i=x,##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=x,##__VA_ARGS__;i<(y);++i)
#define pb emplace_back
#define sz(a) int((a).size())
#define all(a) (a).begin(),(a).end()
#define fi first
#define se second
#define mkp make_pair
typedef long long LL; typedef vector<int> Vi; typedef pair<int,int> Pii;
auto ckmax=[](auto &x,auto y) { return x<y ? x=y,true : false; };
auto ckmin=[](auto &x,auto y) { return y<x ? x=y,true : false; };
sfmt19937 mt(chrono::steady_clock::now().time_since_epoch().count());
int rnd(int l,int r) { return uniform_int_distribution<>(l,r)(mt); }
#define getchar() getchar_unlocked()
struct IO {
template<typename T>IO& operator >> (T &x) {
x=0;bool f=0;char c;while(!isdigit(c=getchar()))f|=c=='-';
do x=x*10+c-48;while(isdigit(c=getchar()));if(f)x=-x;
return *this;
}
} io;
#define cin io
template<typename T=int>T read() { T x; cin>>x; return x; }
const int mod = 998244353;
struct mint {
int x; mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
mint(LL y) { y%=mod, x=y<0?y+mod:y; }
mint& operator += (const mint &y) { x=x+y.x<mod?x+y.x:x+y.x-mod; return *this; }
mint& operator -= (const mint &y) { x=x<y.x?x-y.x+mod:x-y.x; return *this; }
mint& operator *= (const mint &y) { x=1ll*x*y.x%mod; return *this; }
friend mint operator + (mint x,const mint &y) { return x+=y; }
friend mint operator - (mint x,const mint &y) { return x-=y; }
friend mint operator * (mint x,const mint &y) { return x*=y; }
}; mint Pow(mint x,LL y=mod-2) { mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z; }
const int N = 1e6+5;
int n,m,o[N],L[N],R[N],V[N],a[N],b[N];
vector<Pii> q[N];
int fa[N];
int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); }
#define ls (u<<1)
#define rs (u<<1|1)
#define mid (l+r>>1)
struct { int add; Pii mn; } t[N*4];
Pii operator + (const Pii &x,const Pii &y) { return x.fi<=y.fi ? x : y; }
void bld(int u=1,int l=1,int r=o[0]) {
t[u] = {0,{0,l}};
if( l == r ) return;
bld(ls,l,mid), bld(rs,mid+1,r);
}
void add(int ql,int qr,int x,int u=1,int l=1,int r=o[0]) {
if( qr < l || r < ql ) return;
if( ql <= l && r <= qr ) { t[u].add += x, t[u].mn.fi += x; return; }
add(ql,qr,x,ls,l,mid), add(ql,qr,x,rs,mid+1,r);
t[u].mn = t[ls].mn + t[rs].mn, t[u].mn.fi += t[u].add;
}
Pii argmin(int ql,int u=1,int l=1,int r=o[0]) {
if( r < ql ) return {1e9,0};
if( ql <= l ) return t[u].mn;
Pii res = argmin(ql,ls,l,mid) + argmin(ql,rs,mid+1,r);
return res.fi += t[u].add, res;
}
struct {
int t[N];
void clr() { memset(t+1,0,sizeof(int)*o[0]); }
void add(int i) { for(;i;i-=i&-i)++t[i]; }
int sum(int i) { int res=0; for(;i<=o[0];i+=i&-i)res+=t[i]; return res; }
} ft;
void MAIN() {
cin>>n>>m; For(i,1,m) cin>>L[i]>>R[i]>>V[i], o[++o[0]] = V[i];
sort(o+1,o+o[0]+1), o[0] = unique(o+1,o+o[0]+1)-o-1;
For(i,1,m) q[lower_bound(o+1,o+o[0]+1,V[i])-o].pb(L[i],R[i]);
iota(fa+1,fa+n+2,1);
rFor(i,o[0],1) {
sort(all(q[i]),greater<>());
int lst = n+1;
for(auto [l,r] : q[i]) if( r < lst ) {
int p = find(l);
if( p > r ) { cout<<"-1\n"; return; }
a[p] = i, lst = p;
}
for(auto [l,r] : q[i])
for(int p = find(l); p <= r; p = find(p)) b[p] = i, fa[p] = p+1;
}
// cerr<<"a: "; For(i,1,n) cerr<<a[i]<<" "; cerr<<'\n';
// cerr<<"b: "; For(i,1,n) cerr<<b[i]<<" "; cerr<<'\n';
bld();
For(i,1,n) if( a[i] ) add(a[i]+1,o[0],1);
For(i,1,n) {
if( a[i] ) add(a[i]+1,o[0],-1);
else a[i] = argmin(b[i]).se;
add(1,a[i]-1,1);
}
// cerr<<"a: "; For(i,1,n) cerr<<a[i]<<" "; cerr<<'\n';
LL ans = 0;
For(i,1,n) ans += ft.sum(a[i]+1), ft.add(a[i]);
cout<<ans<<'\n';
} signed main() {
#ifdef FT
freopen("in","r",stdin); freopen("out","w",stdout);
#endif
ios::sync_with_stdio(0);
int lft=read(); while( lft-- ) {
MAIN();
ft.clr();
For(i,1,o[0]) q[i].clear();
memset(a+1,0,sizeof(int)*n), memset(b+1,0,sizeof(int)*n);
o[0] = 0;
}
return 0;
}
标签:空位,return,int,题解,冒泡排序,fa,NOI2022,sim,逆序
From: https://www.cnblogs.com/ft61/p/18357848