平面 题解
平面
【问题描述】
二维的空间即是平面。我们在二维空间中定义直角坐标系,并用网格将空间划分为单位面积的一块一块,并给每块一个二维坐标。我们假设有一个小生命生活在二维空间中从(1,1)到(n,m)的共n×m块的矩形区域中,二维生命体一开始可以处于任意一块中,并且可以移动到上下左右相邻的一块中,但是不能越过矩形的边界。现在有一个高维的生命体闯入了这个世界,并开始制造混乱。高维生命体改变了格子的高度,使得没有任意两个相邻格子的高度相同。这样空间就变成了三维空间。但对于二维生命体来说,整个空间还是一个平面,只是它无法从一个高度较低的格子移动到相邻的高度较高的格子。二维生命体可以从任意一个格子开始移动,并在除起点外的任意一个可到达的格子处停下。一条移动的路径定义为沿途经过的所有格子的序列,路径长度为经过的格子数减1。不难发现,路径的条数是有限的。现在告诉你每一块格子的高度,你能求出所有可能路径的长度的0~k次方的和吗?由于答案可能很大,你只需要输出每个答案对12345取模后的结果。
【输入格式】
输入文件的第一行包含三个正整数n、m和k。
接下来的n行每行包含m个绝对值不超过10^9的整数,分别表示每个格子的高度。
【输出格式】
输出k+1行,每行包含一个整数。第i行的整数表示所有可能路径的长度的i−1次方之和对12345取模后的值。
【样例输入】
3 4 3
1 2 3 4
4 3 2 1
1 2 3 4
【样例输出】
38
66
136
318
DP,将格子排序,f[i]表示从i出发的路径数,g[i]为路径总长。f[i]=Σf[j],g[i]=Σ(f[j]+g[j]),j为与i相邻的编号。
s[k][i]为从i出发的路径的k次方和,设到j的长度为aj[1...p],s[k][j]=Σx(aj[x])^k,s[k][i]=ΣjΣx(aj[x]+1)^k。
转移:
令a=1,
复杂度:O(nm log nm +nmk2)
附代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <vector> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <iomanip> 13 #include <ctime> 14 #include <climits> 15 #include <cctype> 16 #include <algorithm> 17 #define clr(x) memset(x,0,sizeof(x)) 18 #define LL long long 19 #ifdef WIN32 20 #define AUTO "%I64d" 21 #else 22 #define AUTO "%lld" 23 #endif 24 25 using namespace std; 26 27 const int N = 300; 28 const int K = 50; 29 const int mod = 12345; 30 const int V[4][2] = {{0,1},{1,0},{0,-1},{-1,0}}; 31 32 class point { 33 public: 34 int x, y, h; 35 point() { } 36 point(int _x, int _y, int _h) : x(_x), y(_y), h(_h) { } 37 bool operator < (const point &p) const { return h < p.h; } 38 } p[N*N+1]; 39 40 int n,m,k,a[N+1][N+1],ans[N+1],C[K+1][K+1],d[N*N+1][K+1]; 41 42 inline int node(int x, int y) { return (x-1)*m+y; } 43 44 int main() { 45 freopen("plane.in","r",stdin); 46 freopen("plane.out","w",stdout); 47 scanf("%d%d%d",&n,&m,&k); 48 C[0][0] = 1; 49 for(int i = 1; i <= k; ++i) { 50 C[i][0] = C[i][i] = 1; 51 for(int j = 1; j < i; ++j) { 52 C[i][j] = C[i-1][j-1]+C[i-1][j]; 53 if(C[i][j] >= mod) C[i][j] -= mod; 54 } 55 } 56 for(int i = 1; i <= n; ++i) 57 for(int j = 1; j <= m; ++j) { 58 scanf("%d", &a[i][j]); 59 p[node(i, j)] = point(i, j, a[i][j]); 60 } 61 sort(p+1, p+n*m+1); 62 for(int i = 1; i <= n * m; ++i) { 63 int r = node(p[i].x, p[i].y); 64 d[r][0] = 1; 65 for(int v = 0; v < 4; ++v) { 66 int x = p[i].x+V[v][0], y = p[i].y+V[v][1]; 67 int q = node(x, y); 68 if(x < 1 || x > n || y < 1 || y > m || a[x][y] >= p[i].h) continue; 69 d[r][0] += d[q][0]; 70 if(d[r][0] >= mod) d[r][0] -= mod; 71 for(int j = 1; j <= k; ++j) 72 for(int l = 0; l <= k; ++l) { 73 d[r][j] += (C[j][l]*d[q][l])%mod; 74 if(d[r][j] >= mod) d[r][j] -= mod; 75 } 76 } 77 for(int j = 0; j <= k; ++j) { 78 ans[j] += d[r][j]; 79 if(ans[j] >= mod) ans[j] -= mod; 80 } 81 } 82 ans[0] -= (n * m) % mod; 83 if(ans[0] < 0) ans[0] += mod; 84 for(int i = 0; i <= k; ++i) printf("%d\n", ans[i]); 85 return 0; 86 }