省选联测39

直接粘题解tmd
前情提要,这里都是我从题解里的md源码,并不是我写的,避免误伤

A.伯爵

我们发现一对排列不一定对应一种方案,一种方案也不一定对应一对排列。

考虑如何不算重。

首先确定的是归并方式:每个排列对应一些划分,相当于把每个划分出的区间按最大值排序。

考虑把\(1..n\)划分成若干集合,使得每个集合在两个排列中都对应若干区间的并,且是极小的。

当然枚举完以后还要讨论集合内的排列方式。

那么这样一种方案对应的排列对的个数为\(2^{不完全相同的集合数}\)

对应的答案序列个数为\(2^{最大值相同但整体不同的划分数}\)

考虑令\(f_i\)表示\(\sum_{一对长度为i的排列使得不能划分成更小的集合}2^{最大值相同但整体不同的划分数}\)

考虑

\[F=\sum_{i\ge 1}{f_i\over i!} \]

可以发现

\[n![x^n]e^{2F}=\sum_{长度为n的排列对}2^{最大值相同的划分数}=\prod_{i=1}^{n}(i^2+1) \\ \]

后面部分的证明考虑1产生的贡献。

发现答案就是\(n![x^n]e^F\)。多项式开根即可。

B.给给的游戏

题目描述

给定 \(n\) 个点的竞赛图 \(G\),对于每条边 \((i,j)\),求解反转该边方向后图 \(G\) 是否联通。

\(1 \leq n \leq 5000\)

文字题解

问题 \(1\):求解竞赛图的一条哈密顿路径

假设求出前 \(i\) 个点的哈密顿路径,加入第 \(i+1\) 个点

  1. 若存在边 \((i+1,v_1)\) 则将 \(i+1\) 放在 \(v_1\) 之前
  2. 若存在边 \((v_i,i+1)\) 则将 \(i+1\) 放在 \(v_i\) 之后
  3. 否则必然存在 \(v_j,v_{j+1}\),满足存在边 \((v_j,i+1),(v_{j+1},i+1)\) 将其插入

问题 \(2\) :求解强连通竞赛图的一条哈密顿回路

我们先求解出一条哈密顿路径,在其之上构造

首先一定存在哈密顿路径的一个前缀满足其构成回路,否则每个点一定均向哈密顿路径之后的点连边,那么图不强连通

之后每次将后面一段未加入回路的路径尝试插入回路中,容易发现最终所有点一定在回路中,证明留作习题

考虑若原图不强连通,那么一定是首尾 \(2\) 个联通块的翻转构成答案 (注意特判 \(n=2\) 的情况)

否则原图强联通,容易发现除去哈密顿回路的边一定满足,我们只需要求解哈密顿回路上的每条边是否可行即可

关于竞赛图是否强联通,可以将所有点按度数排序,尝试比较是否每前 \(i\) 个点向后 \(n-i\) 个点的连边数均为\(i \times (n-i)\),若存在则一定不联通,否则一定联通,证明留作习题。

容易发现反转一条边,可以直接维护增量,复杂度为 \(O(n^2)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=5007; bool tag[N];
int n,k,p[N],w[N],g[N],v[N],q[N],ga[N],gb[N],deg[N],f[N][N],t[N][N]; char s[N];
inline int getval(char w){
	if('0'<=w&&w<='9') return w-'0'; return 10+w-'A';
}
inline char getvas(int w){
	if(0<=w&&w<=9) return w+'0'; return w-10+'A';
}
inline bool cmp(int a,int b){
	return deg[a]>deg[b];
}
inline void solve(int a,int b,int c){
	g[0]=0; int t=1;
	while(a--) g[++g[0]]=w[t++]; g[++g[0]]=b;
	while(c--) g[++g[0]]=w[t++]; for(int x=0;x<=g[0];x++) w[x]=g[x];
}
inline void solve2(int s,int a,int b){
	g[0]=0; int t=1,e=a-s-1;
	while(s--) g[++g[0]]=q[t++];
	for(int i=a;i<=b;i++) g[++g[0]]=w[i];
	while(e--) g[++g[0]]=q[t++];
	for(int x=0;x<=g[0];x++) q[x]=g[x];
}
inline void solve3(int a,int b){
	f[a][b]^=1,f[b][a]^=1;
	g[0]=0,w[0]=0; bool f1=0,f2=0; int c=a,d=b; deg[a]--,deg[b]++;
	if(deg[a]<deg[b]) swap(a,b);
	for(int i=1;i<=p[0];i++){
		if(p[i]==a||p[i]==b) continue; g[++g[0]]=p[i];
	}
	for(int i=1;i<=g[0];i++){
		if(deg[a]>=deg[g[i]]&&!f1) f1=1,w[++w[0]]=a;
		if(deg[b]>=deg[g[i]]&&!f2) f2=1,w[++w[0]]=b;
		w[++w[0]]=g[i];
	}
	if(!f1) w[++w[0]]=a; if(!f2) w[++w[0]]=b; g[0]=0; f1=0,f2=0;
	for(int i=1;i<w[0];i++){
		g[i]=g[i-1];
		if(w[i]==a||w[i]==b){
			if(w[i]==a) f1=1; if(w[i]==b) f2=1;
			for(int x=1;x<i;x++) if(f[w[x]][w[i]]) g[i]--;
			for(int x=i+1;x<=w[0];x++) if(f[w[i]][w[x]]) g[i]++;
		}
		else{
			g[i]=g[i]-ga[w[i]]+gb[w[i]];
			g[i]=g[i]+(f[a][w[i]]&&v[a]<v[w[i]]);
			g[i]=g[i]+(f[b][w[i]]&&v[b]<v[w[i]]);
			g[i]=g[i]-(f[w[i]][a]&&v[a]>v[w[i]]);
			g[i]=g[i]-(f[w[i]][b]&&v[b]>v[w[i]]);
			
			g[i]=g[i]-(f[a][w[i]]&&f1);
			g[i]=g[i]-(f[b][w[i]]&&f2);
			g[i]=g[i]+(f[w[i]][a]&&!f1);
			g[i]=g[i]+(f[w[i]][b]&&!f2);
		}
		if(g[i]==i*(w[0]-i)){
			f[a][b]^=1,f[b][a]^=1,t[a][b]=t[b][a]=0;
			deg[c]++,deg[d]--; return;
		}
	}
	deg[c]++,deg[d]--,f[a][b]^=1,f[b][a]^=1; return;
}
int main(){
	int case_num; cin>>case_num;
	while(case_num--){
		scanf("%d",&n),p[1]=1;
		for(int i=2;i<=n;i++){
			scanf("%s",s+1),k=strlen(s+1),deg[i]=0,p[i]=i;
			for(int j=1;j<=k;j++){
				s[j]=getval(s[j]);
				if(j*4-3<i){ 
					f[i][j*4-3]=((s[j]&1)>0)?1:0;
					f[j*4-3][i]=((s[j]&1)>0)?0:1;
				}
				if(j*4-2<i){
					f[i][j*4-2]=((s[j]&2)>0)?1:0;
					f[j*4-2][i]=((s[j]&2)>0)?0:1;
				}
				if(j*4-1<i){
					f[i][j*4-1]=((s[j]&4)>0)?1:0;
					f[j*4-1][i]=((s[j]&4)>0)?0:1;
				}
				if(j*4-0<i){
					f[i][j*4-0]=((s[j]&8)>0)?1:0;
					f[j*4-0][i]=((s[j]&8)>0)?0:1;
				}
			}
		}
		if(n==2){
			puts("0"); continue;
		}
		for(int i=1;i<=n;i++) deg[i]=0;
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n;j++)
				if(f[i][j]) deg[i]++; else deg[j]++;
		sort(p+1,p+n+1,cmp); bool flag=0; p[0]=n;
		for(int i=1;i<=n;i++) v[p[i]]=i; g[0]=0; ga[p[n]]=gb[p[n]]=0;
		for(int i=1;i<n;i++){
			g[i]=g[i-1],ga[p[i]]=gb[p[i]]=0;
			for(int x=1;x<i;x++) if(f[p[x]][p[i]]) g[i]--,ga[p[i]]++;
			for(int x=i+1;x<=n;x++) if(f[p[i]][p[x]]) g[i]++,gb[p[i]]++;
			tag[i]=(g[i]<i*(n-i)); if(!tag[i]) flag=1;
		}
		if(flag){
			int a=0,b=0;
			for(int i=n;i>=1;i--) if(!tag[i]) a=i;
			for(int i=1;i<n;i++) if(!tag[i]) b=i+1;
			for(int i=1;i<=a;i++)
				for(int j=b;j<=n;j++)
					if(p[i]>p[j]) t[p[i]][p[j]]=1;
					else t[p[j]][p[i]]=1;
		}
		else{
			w[w[0]=1]=1;
			for(int i=1;i<=n;i++)
				for(int j=i+1;j<=n;j++) t[j][i]=1;
			for(int i=2;i<=n;i++){
				if(f[i][w[1]]) solve(0,i,w[0]);
				else if(f[w[w[0]]][i]) solve(w[0],i,0);
				else{
					for(int x=1;x<w[0];x++)
						if(f[w[x]][i]&&f[i][w[x+1]]) {solve(x,i,w[0]-x); break;}
				}
			}
			int j; q[0]=0;
			for(int i=2;i<=n;i++) if(f[w[i]][w[1]]) j=i;
			for(int i=1;i<=j;i++) q[++q[0]]=w[i];
			for(int i=j+1;i<=n;i++){
				for(int x=1;x<j;x++)
					if(f[q[x]][w[j+1]]&&f[w[i]][q[x+1]]){
						solve2(x,j+1,i),j=i; break;
					}
				if(i==j) continue;
				if(f[q[j]][w[j+1]]&&f[w[i]][q[1]]) solve2(j,j+1,i);
			}
			for(int i=1;i<n;i++) solve3(q[i],q[i+1]); solve3(q[n],q[1]);
		}
		for(int i=2;i<=n;i++){
			for(int j=1;(j-1)*4<i-1;j++)
				putchar(getvas(t[i][j*4-3]+2*t[i][j*4-2]+4*t[i][j*4-1]+8*t[i][j*4]));
			puts("");
		}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++) t[i][j]=0;
	}
	return 0;
}

C.一定要关掉

对目录的遍历即为对二叉树的遍历,显然 DLR 为前序遍历,LDR 为中序遍历,LRD 为后序遍历。

  1. 所有排列都能转化成上述三种,例如 RLD 与 DLR 等价,因为它们的序列一定相反。

  2. 由初赛常识,知前中得后,知后中得前,知前后不得中,例如一条链。

答案不超过 \(2\),模拟即可。

D.种树

相当于一下午就改了这一个题,注意要分正负维护保证复杂度,取min操作时要注意其对之后的影响,该还给后边的还得还回去
直接结合题解看码吧,map好维护一点,脑抽了信题解写了set,其实应该是multiset,但是居然没被卡,后来改成multi了


#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=5e5+10;
const int INF=1e6+10;

struct Line{
	int a,b,c,d,id;
	ll Calc(int x)const{ return 1LL*(x-a)*(d-b)+1LL*b*(c-a); }
	bool operator <(const Line&rhs)const{
		if(rhs.a<a)return 1LL*b*(rhs.c-rhs.a)<rhs.Calc(a);
		else return 1LL*Calc(rhs.a)<1LL*rhs.b*(c-a);
	}
}P[maxn];

int n,L,R;
vector<int>E[maxn];
int deg[maxn];

void Link(){
	set<Line>S;priority_queue<pii>q;
	Rep(i,1,n){
		while(!q.empty() && -q.top().fir<P[i].a){ S.erase(P[q.top().sec]);q.pop(); }
		auto it = S.lower_bound(P[i]);
		if(it!=S.end()){ E[it->id].emplace_back(i); ++deg[i]; }
		if(it!=S.begin()){ E[i].emplace_back(prev(it)->id),++deg[prev(it)->id]; }
		S.insert(P[i]);q.emplace(-P[i].c,i);
	}
}

void Dp(){
	multiset<pii>f,g;
	f.insert(pii(0,INF)),g.insert(pii(L-1,-INF));
	f.insert(pii(R,INF));
	queue<int>q;Rep(i,1,n)if(!deg[i])q.push(i);
	auto tmp=f.begin();
	while(!q.empty()){
		int u=q.front();q.pop();
		if(P[u].b>P[u].d){
			auto it = f.lower_bound(pii(P[u].a+1,-INF));
			int sum=0;vector< set<pii>::iterator >vec;
			for(; it!=f.end() && it->fir<=P[u].c; ++it ){
				sum+=it->sec;vec.emplace_back(it);
				auto ip=g.lower_bound(pii(it->fir,-INF));
				if(ip==g.end())continue;
				while(ip!=g.end() && sum+ip->sec>=0 && ip->fir<=P[u].c){
					sum+=ip->sec;tmp=next(ip);
					g.erase(ip);ip=tmp;
				}
				if(sum >0 && ip!=g.end() && ip->fir<=P[u].c){
					int p=ip->fir;
					sum+=ip->sec;
					g.erase(ip);g.insert(pii(p,sum));
					sum=0;
				}
			}
			for(auto ip : vec)f.erase(ip);
			if(sum>0)f.insert(pii(P[u].c+1,sum));
			f.insert(pii(P[u].a,1));g.insert(pii(P[u].c,-1));
		}else{
			auto it = g.upper_bound(pii(P[u].c-1,INF+INF));
			if(it!=g.begin()){
				--it;
			int sum=0;vector< set<pii>::iterator >vec;
			for(; it->fir>=P[u].a ; --it){
				sum+=it->sec;vec.emplace_back(it);
				auto ip=f.upper_bound(pii(it->fir,INF));
				if(ip!=f.begin()){
					--ip;
					while(ip->fir>=P[u].a && sum+ip->sec<=0){
						sum+=ip->sec;
						if(ip==f.begin()){ f.erase(ip); break; }
						tmp=prev(ip);f.erase(ip);ip=tmp;
					}
					if(sum<0 && ip!=f.end() && ip->fir>=P[u].a){
						int p=ip->fir;
						sum+=ip->sec;
						f.erase(ip);f.insert(pii(p,sum));
						sum=0;
					}
				}
				if(it==g.begin())break;
			}
			for(auto ip : vec)g.erase(ip);
			if(sum<0)g.insert(pii(P[u].a,sum));
			}
			f.insert(pii(P[u].a+1,1)),g.insert(pii(P[u].c+1,-1));
		}
		for(auto v : E[u])!(--deg[v]) && (q.push(v),0);
	}
	int ans=n;int sum=0;
	f.insert(pii(L,0));f.insert(pii(R,0));
	f.insert(g.begin(),g.end());
	for(auto it=f.begin();it!=f.end();++it){
		sum+=it->sec;
		if((it->fir>=L && it->fir<=R) && (it==f.end() || it->fir !=(next(it)->fir)))ans=min(ans,sum);
	}
	cout<<ans<<"\n";
}

void solve(){
	cin>>L>>R>>n;Rep(i,1,n)cin>>P[i].a>>P[i].b>>P[i].c>>P[i].d;
	Rep(i,1,n)if(P[i].a>P[i].c)swap(P[i].a,P[i].c),swap(P[i].b,P[i].d);
	sort(P+1,P+n+1,[&](const Line &x,const Line &y){ return x.a<y.a; });
	L*=2,R*=2;Rep(i,1,n)P[i].id=i,P[i].a*=2,P[i].b*=2,P[i].c*=2,P[i].d*=2;
	Link();
	Dp();
		
}

int main (){
	fre(tree);
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0;
}


posted @ 2023-02-24 20:28  Delov  阅读(57)  评论(6编辑  收藏  举报