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;
}