CF 212A 数据范围放大版。
题解:
首先容易发现每个点的 minmax 差不会超过 1 1 1,且差为 1 1 1 当且仅当度数不是 t t t 的倍数。
换言之,只要保证每个点 i i i 分给 j j j 的都在 ⌊ d e g / t ⌋ \lfloor deg/t\rfloor ⌊deg/t⌋ 和 ⌈ d e g / t ⌉ \lceil deg/t\rceil ⌈deg/t⌉ 即可。证明考虑归纳即可。
那么第一个思路就很显然了,考虑归纳,我们先决定哪些边给到 t t t,然后 − − t --t −−t 考虑下一个问题,显然可以直接网络流。
还有一个好点的思路,考虑二分图边染色,我们把每个点拆成若干个点,加边的同时利用增广保证没有重复颜色即可。
代码1(网络流):
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int N=6e2+7,M=1e6+7;
int deg[N];
int bel[M],rec[M];
int a,b,m,k;
int S,T;
int el[N],nx[M],to[M],cap[M],ec=1;
void adde(int u,int v,int c){
nx[++ec]=el[u],el[u]=ec,to[ec]=v,cap[ec]=c;
nx[++ec]=el[v],el[v]=ec,to[ec]=u,cap[ec]=0;
}
int lev[N],gap[N],cur[N],finished;
void BFS(){
memset(lev,0,sizeof lev);
memset(gap,0,sizeof gap);
std::queue<int> q;q.push(T);lev[T]=gap[1]=1;
while(!q.empty()){
int u=q.front();q.pop();cur[u]=el[u];
for(int re e=el[u];e;e=nx[e])
if(!bel[e]&&!lev[to[e]]){
lev[to[e]]=lev[u]+1;
++gap[lev[to[e]]];
q.push(to[e]);
}
}finished=lev[S]==0;
}
int dfs(int u,int flow){
if(u==T)return flow;int ans=0;
for(int &e=cur[u];e;e=nx[e])
if(!bel[e]&&cap[e]&&lev[to[e]]+1==lev[u]){
int dlt=dfs(to[e],std::min(flow-ans,cap[e]));
cap[e]-=dlt;cap[e^1]+=dlt;
if((ans+=dlt)==flow)return ans;
}
if(!--gap[lev[u]])finished=true;
++gap[++lev[u]];cur[u]=el[u];
return ans;
}
int vs[N],idx;
bool fix_flow(int u){
if(vs[u]==idx)return false;
vs[u]=idx;int eu=u+m;
if(cap[eu<<1|1]>deg[u]/k){
--cap[eu<<1|1];
++cap[eu<<1];
return true;
}
for(int re e=el[u];e;e=nx[e])
if(!bel[e]&&rec[e]==cap[e]&&vs[to[e]]!=idx){
vs[to[e]]=idx;int v=to[e];
for(int re r=el[v];r;r=nx[r])
if(!bel[r]&&rec[r]!=cap[r]&&fix_flow(to[r])){
int w=cap[r]<rec[r]?-1:1;
cap[r]-=w,cap[r^1]+=w;
cap[e]-=w,cap[e^1]+=w;
return true;
}
}
return false;
}
void Flow(){
BFS();while(!finished)dfs(S,1e9);
for(int re i=1;i<=a+b;++i)
while(cap[(i+m)<<1|1]<deg[i]/k){
vs[S]=vs[T]=++idx;
assert(fix_flow(i));
++cap[(i+m)<<1|1];
--cap[(i+m)<<1];
}
}
void Main(){
scanf("%d%d%d%d",&a,&b,&m,&k);
S=0,T=a+b+1;
for(int re i=1;i<=m;++i){
int u,v;scanf("%d%d",&u,&v);
++deg[u],++deg[v+a];adde(u,v+a,1);
}
for(int re i=1;i<=a;++i)
adde(S,i,0);
for(int re j=1;j<=b;++j)
adde(j+a,T,0);
for(;k;--k){
for(int re i=1;i<=a+b;++i)
cap[(i+m)<<1]=(deg[i]+k-1)/k,
cap[(i+m)<<1|1]=0;
for(int re i=2;i<=ec;++i)
rec[i]=cap[i];
Flow();
for(int re i=2;i<=m+m+1;++i)
if(rec[i]!=cap[i]){
--deg[to[i]];
bel[i]=k;
}
}
for(int re i=1;i<=m;++i)
cout<<bel[i<<1]<<" ";
}
inline void file(){
#ifdef zxyoi
freopen("divide.in","r",stdin);
#endif
int size=40<<20;//40M
__asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//提交用这个
}signed main(){file();Main();exit(0);}
代码2(二分图边染色):
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int N=3e2+7,M=1e5+7;
int c0,c1;
int nx[2][N+N][N];
void dfs(int o,int x,int y,int cx,int cy){
int to=nx[o^1][y][cx];
nx[o][x][cx]=y;
nx[o^1][y][cx]=x;
if(!to){
nx[o^1][y][cy]=0;
return;
}dfs(o^1,y,to,cy,cx);
}
int a,b,m,k,ans[M];
int sz[2][N],id[2][N];
int eid[N+N][N+N];
void Main(){
scanf("%d%d%d%d",&a,&b,&m,&k);
std::fill(sz[0]+1,sz[0]+a+1,k);
std::fill(sz[1]+1,sz[1]+b+1,k);
for(int re i=1;i<=m;++i){
int u,v;scanf("%d%d",&u,&v);
if(sz[0][u]==k)
sz[0][u]=0,id[0][u]=++c0;
if(sz[1][v]==k)
sz[1][v]=0,id[1][v]=++c1;
++sz[0][u],u=id[0][u];
++sz[1][v],v=id[1][v];
eid[u][v]=i;int cu=1,cv=1;
for(;nx[0][u][cu];++cu);
for(;nx[1][v][cv];++cv);
if(cu==cv){
nx[0][u][cu]=v;
nx[1][v][cv]=u;
}else dfs(0,u,v,cu,cv);
}
for(int re i=1;i<=c0;++i)
for(int re c=1;c<=k;++c)
if(nx[0][i][c])ans[eid[i][nx[0][i][c]]]=c;
for(int re i=1;i<=m;++i)
cout<<ans[i]<<" ";
}
inline void file(){
#ifdef zxyoi
freopen("divide.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}