这道题挺不错的。。反正愚蠢的我没想到这么妙的东西
有种网络流做法 拆拆点搞一搞看看是不是网络流就好 因为bzoj把时限放到了100s 所以就让这种做法过了。。昨天有人还T了 卡了100s 网上面有这里就不写了
在staus有明显的用时分界线。。
我们来说说贪心 为什么我想不到贪心很多年了。。。
不难发现可以用
O(nm)
知道每只兔子在第几天开始能用多少天
这样 在每一天 显然我们尽量用 能用久一点的兔子是更优的
那么在每一天 我们就分别对上一天在用的 以及没在用的分别按能用多少天排个序 在用的从小到大排 没在用的从大到小排
交换前面L个就好了 记得判断一下大小
如果交换之后在用的里面有能用天数=0的 那就无解了
复杂度
O(nlognm)
#include<bits/stdc++.h>
#define me(a,x) memset(a,x,sizeof a)
using namespace std;
const int N=805;
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
return x*f;
}
char a[N][N]; int n,m,p,k,c[N][N],r[N];
bool Cmp1(int A,int B){return r[A]>r[B];}
bool Cmp2(int A,int B){return r[A]<r[B];}
int a1[N],a2[N],ans[N][N]; bool in[N];
int main(){
int i,j; n=read(),m=read(),k=read(),p=read();
for(i=1;i<=n;++i)scanf("%s",a[i]+1);
for(i=1;i<=n;++i)
for(j=m;j;--j)
if(a[i][j]=='1')c[i][j]=c[i][j+1]+1;
else c[i][j]=0;
int l1=0,l2;
for(i=1;i<=n;++i){
r[i]=c[i][1];
if(c[i][1])a1[++l1]=i;
}
sort(a1+1,a1+1+l1,Cmp1);
l1=k; for(i=1;i<=l1;++i)in[a1[i]]=1,ans[1][i]=a1[i];
bool no=0;
for(j=2;j<=m;j++){
l2=0;
for(i=1;i<=n;i++){
r[i]=c[i][j];
if(c[i][j] && !in[i])a2[++l2]=i;
}
sort(a1+1,a1+1+l1,Cmp2);
sort(a2+1,a2+1+l2,Cmp1);
for(i=1;i<=l1;i++){
if(i>l2 || i>p){
if(r[a1[i]]==0)no=1;
break;
}
if(r[a1[i]]>=r[a2[i]])break;
in[a1[i]]=0; in[a2[i]]=1;
a1[i]=a2[i];
}
for(i=1;i<=k;i++)ans[j][i]=a1[i];
if(no)break;
}
if(no)printf("1\n");
else{
for(i=1;i<=m;++i){
for(j=1;j<=k;++j)printf("%d ",ans[i][j]);
printf("\n");
}
}
return 0;
}