BZOJ 2003 [Hnoi2010]Matrix 矩阵

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2003

题解

考虑搜索。

确定了第一行和第一列,那么就确定了整个矩阵,因此搜索的范围可以降到399个位置。

首先搜索第一行,显然每个不是第一行第一列的位置都可以由三个位置唯一确定: ( 1 , 1 ) , ( 1 , i ) , ( j , 1 ) (1,1),(1,i),(j,1) (1,1),(1,i),(j,1)。由于搜索的是第一行,可以把 ( i , j ) (i,j) (i,j)这个位置 = 0 =0 =0 = p − 1 =p-1 =p1都带入一遍,得到的结果就是 ( j , 1 ) (j,1) (j,1)的上下界。如果搜索的过程中发现冲突了那么说明第一行这样填不行,剪枝。

代码

#include <cstdio>
#include <algorithm>
 
int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}
 
const int maxn=200;
 
int n,m,p,a[maxn+10][maxn+10],l[maxn+10][maxn+10],r[maxn+10][maxn+10];
 
int f(int x)
{
  return (x&1)?1:-1;
}
 
int search(int y)
{
  if(y>m)
    {
      return 1;
    }
  for(a[1][y]=0; a[1][y]<p; ++a[1][y])
    {
      int flag=1;
      for(int i=2; i<=n; ++i)
        {
          int b=(0-a[1][1]*f(i+y)-a[1][y]*f(i)-a[i][y])*f(y),c=((p-1)-a[1][1]*f(i+y)-a[1][y]*f(i)-a[i][y])*f(y);
          if(b>c)
            {
              std::swap(b,c);
            }
          l[y][i]=std::max(l[y-1][i],b);
          r[y][i]=std::min(r[y-1][i],c);
          if(l[y][i]>r[y][i])
            {
              flag=0;
              break;
            }
        }
      if(flag)
        {
          if(search(y+1))
            {
              return 1;
            }
        }
    }
  return 0;
}
 
int main()
{
  n=read();
  m=read();
  p=read();
  for(int i=1; i<=n; ++i)
    {
      for(int j=1; j<=m; ++j)
        {
          a[i][j]=read();
        }
    }
  for(int i=2; i<=n; ++i)
    {
      for(int j=2; j<=m; ++j)
        {
          a[i][j]-=a[i-1][j]+a[i][j-1]+a[i-1][j-1];
        }
    }
  for(int i=2; i<=n; ++i)
    {
      l[1][i]=0;
      r[1][i]=p-1;
    }
  for(a[1][1]=0; a[1][1]<p; ++a[1][1])
    {
      if(search(2))
        {
          for(int i=1; i<=n; ++i)
            {
              for(int j=1; j<=m; ++j)
                {
                  if(i==1)
                    {
                      printf("%d%c",a[i][j],(j==m)?'\n':' ');
                    }
                  else if(j==1)
                    {
                      printf("%d%c",l[m][i],(j==m)?'\n':' ');
                    }
                  else
                    {
                      printf("%d%c",a[i][j]+a[1][1]*f(i+j)+a[1][j]*f(i)+l[m][i]*f(j),(j==m)?'\n':' ');
                    }
                }
            }
          return 0;
        }
    }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值