题意简述:给(H , W , h, w)。构造一个(H*W)的矩阵,满足矩阵元素之和为正数,且每个(h*w)的子矩阵元素之和是负数。
感觉是比较简单且比较巧妙的构造题,可惜自己还是太弱,没能做出来。orz wsq
首先考虑第一个样例给出的提示,我们可以在一般位置放1,在满足(i \% h==0,j \% w==0)的位置((i,j))放(-(w*h))。
然后我们考虑有这么一种情况,就是剩下部分的1无法补满之前矩阵贡献的-1,如:(H=1,W=4,h=1,w=3)
我们按照我们的思路就会出现:(1,1,-3,1),然后我们发现总和是小于0的,就会输出no,然而有如下一组可行解:(2,2,-5,2)。
所以我们考虑改进上述构造方法,我们可以在一般位置放k,在满足(i \% h==0,j \% w==0)的位置((i,j))放(-k*(w*h-1)-1),那么我们只要使(k)尽量大,就可以尽可能地补足之前产生的(-1)了。
还有特判(H%h==0,W%w==0)时无解,因为这样只会构造出(frac{H*W}{h*w})个(-1)子矩阵,那么权值和就小于0了。
#include<cstdio>
#include<algorithm>
using namespace std;
int W,H,w,h,sum,ans[510][510],v;
int main(){
scanf("%d%d%d%d",&H,&W,&h,&w);
if(H%h==0&&W%w==0){puts("No");return 0;}
v=500*500/(w*h-1);
for(int i=1;i<=H;i++)
for(int j=1;j<=W;j++){
if(i%h==0&&j%w==0)ans[i][j]=-(w*h-1)*v-1;
else ans[i][j]=v;
sum+=ans[i][j];
}
if(sum>0){
puts("Yes");
for(int i=1;i<=H;i++,puts(""))
for(int j=1;j<=W;j++)
printf("%d ",ans[i][j]);
}
else puts("No");
}