平面 题解

平面
【问题描述】
二维的空间即是平面。我们在二维空间中定义直角坐标系,并用网格将空间划分为单位面积的一块一块,并给每块一个二维坐标。我们假设有一个小生命生活在二维空间中从(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 }

 

posted @ 2017-02-08 11:15  MAVERICK.FREDRICK  阅读(122)  评论(0编辑  收藏  举报