【Atcoder】AGC 016 C

【题意】给定大矩阵的边长H和W,给每格填数(<=|10^9|),要求大矩形总和为正数,而每个h*w的小矩形总和为负数,求构造方式。

【算法】数学

【题解】结论题。

★当h|H&&w|W(H是w的倍数,W是w的倍数)时,每个小矩阵之和加起来翻倍刚好成为大矩阵,无解。

当不为倍数时,显然会有多余的行列,我们尝试一种构造方式使多余的行列起作用。

1.从0计数,在h倍数行全部填正数1000(h-1)-1,在其他行全部填负数-1000(行是倍数时换成列,同理)。

这样构造,在h行范围内只有一行正数,每列之和都是-1。而论总和而言,多余行也有一行正数,小矩阵不满,所以每列至少多出1000-500,解决问题。

2.另一种构造方式,从1计数,在每个h*w倍数处填-1000*(h*w-1)-1,其它地方填1000,这样只要有一多余行列,多的若干个1000就可以将矩阵变成正数。

关键在第一个倍数无解的结论,有解时只要利用多余行列构造即可。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
int read()
{
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c=='-')t=-1;
    do{s=s*10+c-'0';}while(isdigit(c=getchar()));
    return s*t;
}
/*------------------------------------------------------------*/
const int inf=0x3f3f3f3f;
 
int N,M,n,m;
 
int main()
{
    scanf("%d%d%d%d",&N,&M,&n,&m);
    if(N%n==0&&M%m==0){printf("No");return 0;}
    printf("Yes
");
    for(int i=1;i<=N;i++){
        for(int j=1;j<=M;j++)
            printf("%d ",i%n||j%m?1100:-1100*(n*m-1)-1);
        printf("
");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/onioncyc/p/7358734.html