1. 程式人生 > >bzoj2003 [Hnoi2010]矩陣

bzoj2003 [Hnoi2010]矩陣

char int height lan onf 範圍 open 如果 freopen

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

Sample Output

0 0 2
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]$。

然後我們搜索第一行,每搜出一個數就根據這一列的所有數確定第一列的取值範圍,如果不合法就退出搜索。

然後狀態數就神奇地減少了,並且跑得飛快。

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define N (510)
 6 
 7 using namespace std;
 8 
 9 const int f[2]={1,-1};
10 
11 int a[N][N],c[N][N],dn[N][N],up[N][N],n,m,p;
12 13 il int gi(){ 14 RG int x=0,q=1; RG char ch=getchar(); 15 while ((ch<0 || ch>9) && ch!=-) ch=getchar(); 16 if (ch==-) q=-1,ch=getchar(); 17 while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar(); 18 return q*x; 19 } 20 21 il int dfs(RG int j){ 22 if (j>m) return 1; 23 for (a[1][j]=0;a[1][j]<p;++a[1][j]){ 24 RG int fg=1,Min,Max; 25 for (RG int i=2;i<=n;++i){ 26 Min=(c[i][j]+f[(i+j-1)&1]*a[1][1]+f[(i-1)&1]*a[1][j])*f[j&1]; 27 Max=(c[i][j]+f[(i+j-1)&1]*a[1][1]+f[(i-1)&1]*a[1][j]-p+1)*f[j&1]; 28 if (Min>Max) swap(Min,Max); 29 dn[i][j]=max(dn[i][j-1],Min),up[i][j]=min(up[i][j-1],Max); 30 if (dn[i][j]>up[i][j]){ fg=0; break; } 31 } 32 if (fg && dfs(j+1)) return 1; 33 } 34 return 0; 35 } 36 37 int main(){ 38 #ifndef ONLINE_JUDGE 39 freopen("matrix.in","r",stdin); 40 freopen("matrix.out","w",stdout); 41 #endif 42 n=gi(),m=gi(),p=gi(); 43 for (RG int i=1;i<=n;++i) 44 for (RG int j=1,x;j<=m;++j) 45 x=gi(),c[i][j]=x-c[i-1][j]-c[i][j-1]-c[i-1][j-1],up[i][j]=p-1; 46 for (a[1][1]=0;a[1][1]<p && !dfs(2);++a[1][1]); 47 for (RG int i=2;i<=n;++i) a[i][1]=dn[i][m]; 48 for (RG int i=1;i<=n;++i) 49 for (RG int j=1;j<=m;++j) 50 printf("%d%s",c[i][j]+f[(i+j-1)&1]*a[1][1]+f[(i-1)&1]*a[1][j]+f[(j-1)&1]*a[i][1],j<m ? " " : "\n"); 51 return 0; 52 }

bzoj2003 [Hnoi2010]矩陣