Description
Input
第一行包含三个正整数N M P表示矩阵的行数列数以及每个数的范围,接下来N行每行包含M个非负整数,其中第i行第j个数表示以格子(i,j)为右下角的2*2子矩阵中的数的和。保证第一行与第一列的数均为0,且每个和都不超过4(P-1)。
Output
包含N行,每行M个整数,描述你求出的矩阵,相邻的整数用空格分开。(行末不要有多余空格)
Sample Input
3 3 3
0 0 0
0 4 5
0 5 3
0 0 0
0 4 5
0 5 3
Sample Output
0 0 2
2 2 1
1 0 0
2 2 1
1 0 0
HINT
1<=N,M<=200
1<P<=10
正解:搜索。
好像还是寒假的时候就考过这题,然而当时在爆刚另外一题以至于这题连暴力都没写。。
然而现在还是不会做,感觉这题真的好难啊。。
于是我自己肯定是讲不清楚的,所以给一个题解吧:HNOI2010题解 (里面有一个指数写错了)
还是简单提一下,大概就是先构造一个矩阵$c$,它是满足和性质的一个答案,但每个数的取值范围不一定合法。
然后我们又可以发现答案矩阵之和矩阵的第一行和第一列有关,进一步可以发现$a[i][j]$只与$c[i][j],a[1][1],a[1][j],a[i][1]$有关。
然后可以得到$a[i][j]=c[i][j]+(-1)^{i+j-1}a[1][1]+(-1)^{i-1}a[1][j]+(-1)^{j-1}a[i][1]$。
然后我们搜索第一行,每搜出一个数就根据这一列的所有数确定第一列的取值范围,如果不合法就退出搜索。
然后状态数就神奇地减少了,并且跑得飞快。
#include <bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define N (510) using namespace std; const int f[]={,-}; int a[N][N],c[N][N],dn[N][N],up[N][N],n,m,p; il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-,ch=getchar();
return q*x;
} il int dfs(RG int j){
if (j>m) return ;
for (a[][j]=;a[][j]<p;++a[][j]){
RG int fg=,Min,Max;
for (RG int i=;i<=n;++i){
Min=(c[i][j]+f[(i+j-)&]*a[][]+f[(i-)&]*a[][j])*f[j&];
Max=(c[i][j]+f[(i+j-)&]*a[][]+f[(i-)&]*a[][j]-p+)*f[j&];
if (Min>Max) swap(Min,Max);
dn[i][j]=max(dn[i][j-],Min),up[i][j]=min(up[i][j-],Max);
if (dn[i][j]>up[i][j]){ fg=; break; }
}
if (fg && dfs(j+)) return ;
}
return ;
} int main(){
#ifndef ONLINE_JUDGE
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
#endif
n=gi(),m=gi(),p=gi();
for (RG int i=;i<=n;++i)
for (RG int j=,x;j<=m;++j)
x=gi(),c[i][j]=x-c[i-][j]-c[i][j-]-c[i-][j-],up[i][j]=p-;
for (a[][]=;a[][]<p && !dfs();++a[][]);
for (RG int i=;i<=n;++i) a[i][]=dn[i][m];
for (RG int i=;i<=n;++i)
for (RG int j=;j<=m;++j)
printf("%d%s",c[i][j]+f[(i+j-)&]*a[][]+f[(i-)&]*a[][j]+f[(j-)&]*a[i][],j<m ? " " : "\n");
return ;
}