专栏文章

题解:CF1085G Beautiful Matrix

CF1085G题解参与者 2已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@miprcqa5
此快照首次捕获于
2025/12/03 16:41
3 个月前
此快照最后确认于
2025/12/03 16:41
3 个月前
查看原文

Solution

这种奶龙题目是怎么被评上黑题的?
考虑你怎么对 A\le A 的东西进行计数,其中 \le 表示的是字典序。方法基本上都是,先固定一个前缀和 AA 相同,再枚举前缀的下一位使他比 AA 小。在本题中,这种方法计算总量为 O(n3)O(n^3),显然不能通过。
不过我们假装 n500n \le 500,看剩下的怎么算。
容易发现,如果我们在 ii 行,那么剩下 nin-i 行每一行都是一个错排,所以乘上 D(n)niD(n)^{n-i},剩下的只需要考虑第 ii 行内部的事(D(n)D(n) 是错排数。)
假设我们在第 jj 列填了 kk
如果 i=1i=1,剩下的 njn-j 个数可以随便填,所以方案数是 (nj)!(n-j)!;否则,剩下的 njn-j 个数中,有 tt 个不能放在自己对应的位置下面
dpi,jdp_{i,j} 表示,有 ii 个数,其中有 jj 个数不能填在特定的位置(这些位置互不相同)的方案数。类似错排,很容易写出递推式:
dpi,j=(j1)dpi1,j2+(ij)dpi1,j1dp_{i,j} = (j-1) dp_{i-1,j_2} + (i-j) dp_{i-1,j-1}
所以乘上 dpnj,tdp_{n-j,t} 即可。
tt 是什么呢?容易发现,实际上就是不在集合 {ai1,1,ai,1,,ai1,j,k}\{a_{i-1,1},a_{i,1},\cdots,a_{i-1,j},k\} 中的元素个数。
S={ai1,1,ai,1,,ai1,j}S=\{a_{i-1,1},a_{i,1},\cdots,a_{i-1,j}\}。那么我们需要求出对于所有 <ai,j< a_{i,j} 且未在 {ai,1,,ai,j1}\{a_{i,1},\cdots,a_{i,j-1}\} 中出现的 kk,求出 S{k}S \cup \{k\} 的集合大小。发现这个只有两种情况,分别是 S|S|S+1|S|+1,使用树状数组统计一下即可。
复杂度 O(n2logn)O(n^2 \log n)
CPP
#include<bits/stdc++.h>
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=5e7+10,MAXM=4e5+10;
const double alpha=1.0-sqrt(2.0)/2.0;
struct Node {int lson,rson,sze,sum;bool flp;}t[MAXN];
int rt,n,q,tot,rev[MAXM],ori[MAXM];
int get_node(void) {return ++tot;}
int push_up(int u,int v) {
	int rt=get_node();
	return t[rt]={u,v,t[u].sze+t[v].sze,t[u].sum+t[v].sum,0},rt;
}
int add_tag(int u) {
	if(!u) return 0;
	int rt=get_node();
	return t[rt]=t[u],swap(t[rt].lson,t[rt].rson),t[rt].flp^=1,rt;	
}
void push_down(int u) {
	if(t[u].flp) t[u].flp=0,t[u].lson=add_tag(t[u].lson),t[u].rson=add_tag(t[u].rson);
	return ;
}
int merge(int u,int v) {
	if(!u||!v) return u|v;
	if(t[u].sze>=(t[u].sze+t[v].sze)*alpha&&t[v].sze>=(t[u].sze+t[v].sze)*alpha) return push_up(u,v);
	if(t[u].sze<=t[v].sze) {
		push_down(v);
		int l=t[v].lson,r=t[v].rson;
		if(t[r].sze>=(t[u].sze+t[v].sze)*alpha&&t[l].sze+t[u].sze>=(t[u].sze+t[v].sze)*alpha) return merge(merge(u,l),r);
		push_down(l);
		int ll=t[l].lson,rr=t[l].rson;
		return merge(merge(u,ll),merge(rr,r));
	}
	else {
		push_down(u);
		int l=t[u].lson,r=t[u].rson;
		if(t[l].sze>=(t[u].sze+t[v].sze)*alpha&&t[r].sze+t[v].sze>=(t[u].sze+t[v].sze)*alpha) return merge(l,merge(r,v));
		push_down(r);
		int ll=t[r].lson,rr=t[r].rson;
		return merge(merge(l,ll),merge(rr,v));
	}
}
void split(int u,int v,int &x,int &y) {
	if(!u) return x=y=0,void();
	if(!v) return x=0,y=u,void();
	if(v==t[u].sze) return x=u,y=0,void();
	push_down(u);
	if(v<=t[t[u].lson].sze) return split(t[u].lson,v,x,y),y=merge(y,t[u].rson),void();
	return split(t[u].rson,v-t[t[u].lson].sze,x,y),x=merge(t[u].lson,x),void();
}
int find_pos(int u,int v) {
	push_down(u);
	if(t[u].lson==0) return 1;
	if(t[t[u].lson].sum>=v) return find_pos(t[u].lson,v);
	return find_pos(t[u].rson,v-t[t[u].lson].sum)+t[t[u].lson].sze;
}
void del(int l,int r) {
	int A,B,C;
	split(rt,r,A,C),split(A,l-1,A,B);
	return rt=merge(A,C),void();
}
int nflp[50],flp[50];
void copy(int l,int r,int k,int op) {
	int A,B,C;
	split(rt,r,A,C),split(A,l-1,A,B);
	nflp[0]=B;
	int empt=0;
	int mx=log2(k)+1;
	if(op==0) {
		ffor(i,1,mx) nflp[i]=merge(nflp[i-1],nflp[i-1]);
		ffor(i,0,mx) if(k&(1<<i)) empt=merge(empt,nflp[i]);
		return rt=merge(merge(A,empt),C),void();
	}
	else {
		flp[0]=add_tag(B);
		ffor(i,1,mx) flp[i]=merge(flp[i-1],nflp[i-1]),nflp[i]=merge(nflp[i-1],flp[i-1]);
		int empt=0,cnt=0;
		roff(i,mx,0) if(k&(1<<i)) {
			if(cnt) empt=merge(empt,flp[i]);
			else empt=merge(empt,nflp[i]);
			cnt^=1;
		}
		return rt=merge(merge(A,empt),C),void();
	}
}
void build(int k,int l,int r) {
	tot=max(tot,k);
	int mid=l+r>>1;
	if(l==r) return t[k]={0,0,1,ori[l],0},void();
	build(k<<1,l,mid),build(k<<1|1,mid+1,r);	
	t[k]={k<<1,k<<1|1,t[k<<1].sze+t[k<<1|1].sze,t[k<<1].sum+t[k<<1|1].sum,0};
	return ;
}
string S;
void output(int rt) {
	if(t[rt].lson==0) return cout<<t[rt].sum,void();
	output(t[rt].lson),output(t[rt].rson);
	return ;
}
int main() {
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>S,S="&"+S;
	ffor(i,1,n) ori[i]=S[i]-'0';
	build(1,1,n),rt=1;
	cin>>q;
	ffor(i,1,q) {
		int op; cin>>op;
		if(op==1) {int l,r,k;cin>>l>>r>>k,copy(l,r,k,0);}
		if(op==2) {int l,r,k;cin>>l>>r>>k,copy(l,r,k,1);}
		if(op==3) {int l,r;cin>>l>>r,del(l,r);}
		if(op==4) {
			int pos; cin>>pos;
			if(pos>t[rt].sum) cout<<-1<<'\n'; else cout<<find_pos(rt,pos)<<'\n';	
		}
	}
	return 0;
}

评论

2 条评论,欢迎与作者交流。

正在加载评论...