2021CSP-S题解

T1 题解

反正也是场外选手,题目没看到 \(先到先得\) 既然不是先到先得的话,那么不是非常的难弄。

首先如果我预处理出 \(f_1,f_2,f_{...},f_{m_1}\) \(f_i\) 表示分配给国内区 \(i\) 个廊桥的最大数量,那么 \(f_{i+1}\) 所选的廊桥肯定包含了\(f_i\) 中所选的廊桥。然后另国外区为 \(g_i\)

然后答案就是 $max(f_i + g_{n-i}) , i \in [0,n] $

现在的任务就是预处理出 \(f\)\(g\) 了。

因为 \(f_{i+1}\) 包含了 \(f_i\) 中所选的廊桥。那么现在的任务想想是什么

对于若干个区间,每次大于上一次的 \(r\)\(l_i\) 最小的一个。每次二分就行了

时间复杂度 \(O(n\log n)\)

T3 题解

T3 难度明显低于 T2 。

场外选手上课时想到了一个贪心做法,是错误的,可惜正反做拿了 96 分。

首先说一下被假掉的贪心算法,基于一个假结论:

一定会有一个 \(1,2,3, ... ,n\) 连续出现在数列中。并且如果有答案,答案在最右侧。

这个算法成功的被假掉了,但是仍有 96

我们观察一下这道题目,第一个只有两种情况,这里选择去讨论这两种情况。

为什么想到在这里分类,按照常理来说在这里分类的话是很难有进一步的发展的,因为似乎有一种嵌套结构。

但是这题不,因为取完第一个之后剩下两个数列就永远会分开而且只能取两边,取完第一个剩下来的操作是一样的,而取第一个的时候是不含嵌套结构的。

想到这点,只需要稍微想一下分类之后怎么做了。

这里只讨论一下一开始取 \(L\) 的情况。

用两个双端队列 \(q_1,q_2\) 去记录一下在另一个和 \(a_L\) 配对的数,然后把它们放进队列。

稍微判断一下 \(q_1,q_2\) 的首尾就好了,注意判断的顺序。

#include <bits/stdc++.h>
#define debug puts("I love Newhanser forever!!!!!");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
    t=0; register char ch=getchar(); register int fflag=1;
    while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
    while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
const int MAXN=3000086;
int n,d[MAXN],a[MAXN],b[MAXN],t[MAXN];
deque<int>q1,q2;
bool check(int pos){
	string ans="",ans1="L";
	ans+=(pos==1)?'L':'R';
	while(!q2.empty())q2.pop_back();
	while(!q1.empty())q1.pop_back();
	if(pos==1){
		for(int i=2;i<t[1];++i) q1.pb(i);
		for(int i=n*2;i>t[1];--i) q2.pb(i);
	}else{
		for(int i=1;i<t[n*2];++i) q1.pb(i);
		for(int i=n*2-1;i>t[2*n];--i) q2.pb(i);
	}
	while(!q1.empty()||!q2.empty()){
		int x=0,y=0,xx=0,yy=0;
		if(!q1.empty()) x=q1.front(),xx=q1.back();
		if(!q2.empty()) y=q2.front(),yy=q2.back();
		if(x&&xx==t[x]){
			q1.pop_front(); 
			q1.pop_back();
			ans+='L';ans1+='L';
			continue;
		}
		if(x&&yy==t[x]){
			q1.pop_front(); 
			q2.pop_back();
			ans+='L';ans1+='R';
			continue;
		}
		if(y&&xx==t[y]){
			q2.pop_front(); 
			q1.pop_back();
			ans+='R';ans1+='L';
			continue;
		}
		if(y&&yy==t[y]){
			q2.pop_front(); 
			q2.pop_back();
			ans+='R';ans1+='R';
			continue;
		}
		return 0;
	}
	cout<<ans;
	for(int i=ans1.size()-1;i>=0;--i) cout<<ans1[i];
	puts("");
	return 1;
}
int main(){
	int T;
	read(T);
	while(T--){
		read(n);
		memset(b,0,sizeof(b));
		memset(t,0,sizeof(t));
		for(int i=1;i<=2*n;++i){
			read(a[i]);
			if(b[a[i]]) t[i]=b[a[i]],t[b[a[i]]]=i;
			else b[a[i]]=i;
		}
		if(!check(1)&&!check(n)) puts("-1");
	}
    return 0;
}

T4 题解

明显网络流,直接建图

#include<bits/stdc++.h>
const int A=360000,B=1210000,INF=1000000000; 
using namespace std;
int n,m,s,t,T,to[A][2],is[A],hd[A],hu[A],lvl[A],qwq[A],tl,van;
struct edge
{
	int to,nt,cap;
}e[B];
void add(int u,int v,int w)
{
	e[tl].to=v,e[tl].nt=hd[u],e[tl].cap=w;
	hd[u]=tl++;
}
bool bfs()
{
	for(int i=0;i<van;++i)hu[i]=hd[i],lvl[i]=van+1;
	int l=0,r=0;
	lvl[s]=0,qwq[r++]=s;
	while(l<r)
	{
		int u=qwq[l++];
		for(int z=hd[u];z!=-1;z=e[z].nt)
		{
			int v=e[z].to;
			if(e[z].cap>0&&lvl[u]+1<lvl[v])
				lvl[v]=lvl[u]+1,qwq[r++]=v;
		}
	}
	return lvl[t]<=van;
}
int dfs(int u,int f)
{
	if(!f||u==t)return f;
	int res=0;
	for(int &z=hu[u];z!=-1;z=e[z].nt)
	{
		int v=e[z].to;
		if(e[z].cap>0&&lvl[u]+1==lvl[v])
		{
			int c=dfs(v,min(e[z].cap,f));
			e[z].cap-=c,f-=c,e[z^1].cap+=c,res+=c;
			if(!f)break; 
		}
	}
	return res;
}
int main()
{
	scanf("%d%d%d",&n,&m,&T);
	for(int i=0,ti=0;i+1<n;++i)
		for(int j=0;j<m;++j,++ti)
			scanf("%d",&to[ti][0]);
	for(int i=0,ti=0;i<n;++i,++ti)
		for(int j=0;j+1<m;++j,++ti)
			scanf("%d",&to[ti][1]);
	for(int i=0;i<m;++i)is[i]=i;
	for(int i=0;i<n;++i)is[m+i]=i*m+m-1;
	for(int i=0;i<m;++i)is[m+n+i]=(n-1)*m+m-1-i;
	for(int i=0;i<n;++i)is[m+m+n+i]=(n-1-i)*m;
	while(T--)
	{
		tl=0;
		van=n*m;
		s=van++,t=van++;
		for(int i=van-1;i>=0;--i)hd[i]=-1;
		for(int i=0,ti=0;i+1<n;++i)
			for(int j=0;j<m;++j,++ti)
				add(ti,ti+m,to[ti][0]),
				add(ti+m,ti,to[ti][0]);
		for(int i=0,ti=0;i<n;++i,++ti)
			for(int j=0;j+1<m;++j,++ti)
				add(ti,ti+1,to[ti][1]),
				add(ti+1,ti,to[ti][1]);
		int k;
		scanf("%d",&k);
		for(int i=0;i<k;++i,++van)
		{
			int x3,p,ok;
			hd[van]=-1;
			scanf("%d%d%d",&x3,&p,&ok);
			add(is[p-1],van,x3),
			add(van,is[p-1],x3);
			if(ok)
				add(s,van,INF),
				add(van,s,0);
			else
				add(van,t,INF),
				add(t,van,0); 
		}
		int res=0;
		while(bfs())res+=dfs(s,INF);
		printf("%d\n",res);
	}
	return 0;
} 
posted @ 2022-06-05 21:08  Mercury_City  阅读(68)  评论(0编辑  收藏  举报