这题还是个思维好题的
我貌似是一个错误的做法水过去了
我们先一问一问的来考虑
首先考虑第一问。
首先,对于每一个导师,由于每一个战队的人员有限制,所以我们将每一个导师的点连向 T T T,流量是战队的人数。
由于存在一个优先级的问题,所以我们不难发现,可以从第一个人开始枚举,依次进行导师的确定。
对于当前的人,我们按照志愿从小到大的顺序来进行连边,记录下来当前志愿有哪些导师,然后连边,如果当前情况下最大流在某一个志愿大于0,那么就表示可以匹配这个志愿,更新
a
n
s
ans
ans数组。
(需要注意的是,同一个志愿的导师要一起连边。)
这里为了剪枝,我们需要把那些没有导师匹配的选手的边都删除,也就是直接将
p
o
i
n
t
point
point和
c
n
t
cnt
cnt复原就
o
k
ok
ok
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) num[j]=0;
for (int j=1;j<=m;j++)
{
if (!a[i][j]) continue;
++num[a[i][j]];
v[a[i][j]][num[a[i][j]]]=j;
}
insert(s,i,1);
for (int j=1;j<=m;j++)
{
int pre = cnt;
for (int i=1;i<=t;i++) b[i]=point[i];
for (int k=1;k<=num[j];++k)
insert(i,v[j][k]+n,1);//,cout<<i<<" "<<v[j][k]<<" "<<"****"<<endl;
int now = dinic();
if (now==1)
{
ans[i]=j;
break;
}
else
{
cnt=pre;
for (int i=1;i<=t;i++) point[i]=b[i];
}
}
for (int j=1;j<=t;j++) s1[i][j]=point[j];
for (int j=1;j<=cnt;j++) s2[i][j]=nxt[j],s3[i][j]=to[j],s4[i][j]=val[j];
ymh[i]=cnt;
}
那么这样第一问就解决了,现在考虑第二问,我们会发现,每一个人的需要上升的名次具有二分性,由于我们要求最少的上升名次,所以可以直接二分。
但是(经过测试),我们发现,如果每次二分然后直接暴力建图重新跑,是会
t
l
e
tle
tle的,这时候,我们选择的方法是戏省空间换时间,在第一问的时候,没算完一个人就记录一下当前状态的邻接表数组,然后我们对于二分到
k
k
k这个排名,可以直接将
1
到
k
−
1
1到k-1
1到k−1的边都直接用
f
o
r
for
for赋值过来,然后处理当前人,这样就不会$
t
l
e
tle
tle了
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 450;
const int maxm = 2e5+1e2;
const int inf = 1e9;
const int N = 80010;
int cnt=1,n,m;
int point[maxn],nxt[maxm],to[maxm],val[maxm];
int h[maxn];
int a[maxn][maxn];
int res[maxn];
int ans[maxn];
int c,t;
int s;
int p[maxn];
int s1[maxn][maxn];
int s2[210][N];
int s3[210][N];
int s4[210][N];
int ymh[maxn];
void addedge(int x,int y,int w)
{
nxt[++cnt]=point[x];
to[cnt]=y;
val[cnt]=w;
point[x]=cnt;
}
void insert(int x,int y,int w)
{
addedge(x,y,w);
addedge(y,x,0);
}
queue<int> q;
bool bfs(int s)
{
memset(h,-1,sizeof(h));
h[s]=0;
q.push(s);
while (!q.empty())
{
int x = q.front();
q.pop();
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (val[i]>0 && h[p]==-1)
{
h[p]=h[x]+1;
q.push(p);
}
}
}
//cout<<"lwk"<<endl;
if (h[t]==-1) return false;
return true;
}
int dfs(int x,int low)
{
if (x==t || low==0) return low;
int totflow=0;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (h[p]==h[x]+1 && val[i]>0)
{
int tmp = dfs(p,min(low,val[i]));
val[i]-=tmp;
val[i^1]+=tmp;
low-=tmp;
totflow+=tmp;
if (low==0) return totflow;
}
}
if (low>0) h[x]=-1;
return totflow;
}
int dinic()
{
int ans=0;
while (bfs(s)) ans+=dfs(s,inf);
return ans;
}
int v[maxn][maxn];
int num[maxn];
void init()
{
cnt=1;
memset(point,0,sizeof(point));
memset(a,0,sizeof(a));
memset(res,0,sizeof(res));
memset(p,0,sizeof(p));
memset(ans,0,sizeof(ans));
memset(num,0,sizeof(num));
memset(ymh,0,sizeof(ymh));
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
memset(s3,0,sizeof(s3));
memset(s4,0,sizeof(s4));
}
int T;
int b[maxn];
bool check(int x,int st)
{
cnt=1;
memset(point,0,sizeof(point));
int uu = m+1;
cnt = ymh[x-1];
for (int i=1;i<=t;i++) point[i]=s1[x-1][i];
for (int i=2;i<=cnt;i++) nxt[i]=s2[x-1][i],to[i]=s3[x-1][i],val[i]=s4[x-1][i];
int i = st;//cout<<cnt<<" "<<st<<" "<<nxt[2]<<" "<<to[2]<<" "<<point[2]<<endl;
for (int j=1;j<=m;j++) num[j]=0;
for (int j=1;j<=m;j++)
{
if (!a[i][j]) continue;
++num[a[i][j]];
v[a[i][j]][num[a[i][j]]]=j;
}
insert(s,i,1);
for (int j=1;j<=m;j++)
{
int pre = cnt;
for (int i=1;i<=t;i++) b[i]=point[i];
for (int k=1;k<=num[j];++k)
insert(i,v[j][k]+n,1);//,cout<<i<<" "<<v[j][k]<<" "<<"****"<<endl;
int now = dinic();
if (now==1)
{
uu=j;
break;
}
else
{
cnt=pre;
for (int i=1;i<=t;i++) point[i]=b[i];
}
}
//cout<<uu<<endl;
if (uu<=p[st]) return true;
return false;
}
int solve(int now)
{
int l=1,r=now,ans=0;
while (l<=r)
{
int mid =l+r >> 1;
if (check(mid,now)) ans=mid,l=mid+1;
else r=mid-1;
}
//cout<<"******"<<endl;
//check(1,2);
//cout<<ans<<endl;
return abs(ans-now);
}
int main()
{
//freopen("yyy.in","r",stdin);
//freopen("yyy.out","w",stdout);
T=read(),c=read();
while (T--)
{
init();
n=read(),m=read();
s=maxn-8;
t=s+1;
for (int i=1;i<=m;i++) res[i]=read();
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
a[i][j]=read();
for (int i=1;i<=n;i++) p[i]=read();
for (int i=1;i<=m;i++) insert(i+n,t,res[i]);//,cout<<res[i]<<"((("<<endl;;
ymh[0]=cnt;
for (int j=1;j<=t;j++) s1[0][j]=point[j];
for (int j=1;j<=cnt;j++) s2[0][j]=nxt[j],s3[0][j]=to[j],s4[0][j]=val[j];
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) num[j]=0;
for (int j=1;j<=m;j++)
{
if (!a[i][j]) continue;
++num[a[i][j]];
v[a[i][j]][num[a[i][j]]]=j;
}
insert(s,i,1);
for (int j=1;j<=m;j++)
{
int pre = cnt;
for (int i=1;i<=t;i++) b[i]=point[i];
for (int k=1;k<=num[j];++k)
insert(i,v[j][k]+n,1);//,cout<<i<<" "<<v[j][k]<<" "<<"****"<<endl;
int now = dinic();
if (now==1)
{
ans[i]=j;
break;
}
else
{
cnt=pre;
for (int i=1;i<=t;i++) point[i]=b[i];
}
}
for (int j=1;j<=t;j++) s1[i][j]=point[j];
for (int j=1;j<=cnt;j++) s2[i][j]=nxt[j],s3[i][j]=to[j],s4[i][j]=val[j];
ymh[i]=cnt;
}
//cout<<endl;
for (int i=1;i<=n;i++)
{
if (!ans[i]) ans[i]=m+1,cout<<m+1<<" ";
else cout<<ans[i]<<" ";
}
cout<<"\n";
for (int i=1;i<=n;i++)
if (ans[i]>p[i])
cout<<solve(i)<<" ";
else cout<<0<<" ";
cout<<endl;
}
return 0;
}