[海军国际项目办公室]秘密探头
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[海军国际项目办公室]秘密探头相关的知识,希望对你有一定的参考价值。
秘密探头
题面
题解
首先,我们很容易将此题转化成一个二分图的模型。
很明显,一次进肯定要与一次出相匹配,而没有与其它操作相匹配的进与出,就相当于是让一开始就留在据点里或者最后都没能走出据点。
我们想让最少的人留在据点里面,相当于就是让没匹配的进操作最少,换言之也就是匹配的数量最多。
而一个操作能够匹配的的操作明显是有限的,确定编号的进操作明显不可能在下一个与它编号一样的确定编号的操作到来之后还与其它操作匹配,它只能与那个操作前的出操作匹配,对于出操作我们也有同样的限制。
于是,我们很好通过上面的叙述建出一张二分图来,两个可以互相匹配的操作之间连边。
但如果我们的匹配呈现出这种这种情况呢?这明显是不合法的。
但我们知道,出现这种情况肯定是有
0
0
0在作祟,两个编号固定的点是不可能越过另一个与别的点进行匹配的,其中必定有两个
0
0
0。
所以,当我们将两者交换后,得到的匹配仍然是合法的匹配,所以对于这种匹配我们是没必要操心的,直接求出我们二分图的最大匹配即可。
但显然我们的匹配不是普通的最大匹配,它是有要求的。
对于一个编号确定的操作,如果它后面还有与它一样的编号确定的操作,它是必须要有匹配点的,否则它一定无法有合法的答案,我们就该判无解了。
所以我们的二分图匹配就应该要要求有点必须与其它点匹配,我们也就不能用普通的匈牙利算法了,而要用匈牙利[alter](顺便加上一个Lily)。
也就是我们要用贪心的方法去匹配二分图,显然匈牙利的方法是如果你匹配被匹配了,那你以后一定是处于匹配状态的,只是对象可能会变,通过这样的增广路径性质,我们可以用更改枚举顺序的方法使得我们的答案尽可能满足条件。
也就是先匹配被限定的点和先增广没被匹配的点,再尝试增广已经匹配的点之内什么的。
注意一定要加上匈牙利的类当前弧优化,否则会T得很惨。
时间复杂度
O
(
n
3
)
O\\left(n^3\\right)
O(n3)?事实上跑得很快,最慢的点都只有
100
m
s
100ms
100ms。
反正能过就对了。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,T,p[MAXN],head[MAXN],tot,L[MAXN],R[MAXN],ans;
struct edge{int to,nxt;}e[MAXN*MAXN];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
struct ming{char opt[5];int id;}s[MAXN];
int match(int x){
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(!p[v]){p[v]=x;return v;}
}
for(int i=head[x];i;head[x]=i=e[i].nxt){
int v=e[i].to;
if(p[v]<x){
if(match(p[v])){p[v]=x;return v;}
else if(R[x]<=n&&R[p[v]]==n+1){p[v]=x;return v;}
}
}
return 0;
}
bool import(int j){return L[j]>0||R[j]<=n;}
signed main(){
read(T);
while(T--){
read(n);
for(int i=1;i<=n;i++)scanf("%s %d",s[i].opt+1,&s[i].id);
for(int i=1;i<=n;i++)L[i]=0,R[i]=n+1;bool flag=0;
for(int i=1;i<=n;i++){
if(!s[i].id)continue;
for(int j=i+1;j<=n;j++)
if(s[i].id==s[j].id){R[i]=j;break;}
for(int j=i-1;j>0;j--)
if(s[i].id==s[j].id){L[i]=j;break;}
}
for(int i=1;i<=n;i++)
if(s[i].opt[1]=='E'){
for(int j=i+1;j<=min(R[i],n);j++)
if(s[j].opt[1]=='L'&&L[j]<=i)
if(!s[j].id||(!import(j)&&!s[i].id))
addEdge(i,j),addEdge(j,i);
for(int j=i+1;j<=min(R[i],n);j++)
if(s[j].opt[1]=='L'&&L[j]<=i)
if(s[j].id&&(s[j].id==s[i].id||(!s[i].id&&import(j))))
addEdge(i,j),addEdge(j,i);
}
for(int i=1;i<=n;i++)if(s[i].opt[1]=='E'){
for(int j=1;j<=n;j++)if(p[j]==i)p[j]=0;
if(!match(i)){if(R[i]<=n){flag=1;break;}}
}
for(int i=1;i<=n;i++){
if(s[i].opt[1]=='E'){ans++;continue;}
if(p[i])ans--;else if(L[i]>0){flag=1;break;}
}
if(flag)puts("OTHER");else printf("%d\\n",ans);
for(int i=1;i<=n;i++)p[i]=head[i]=0;tot=ans=0;
}
return 0;
}
谢谢!!!
以上是关于[海军国际项目办公室]秘密探头的主要内容,如果未能解决你的问题,请参考以下文章