平面 题解

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

平面 题解的相关文章

【题解】平面最近点对(加强版)

洛谷P1429 很久以前就见过并想做的一道题-- 但大概是那个时候太蒻竟然一直不敢做呢,想想时间真的过得好快,从写'Hello World'到如今,其实也不过是短短的一个学期呀. 这道题主要用分治的思想来做,对所有的点排一下序,然后每一次分成两队来处理.若一队的节点数<=3那么就直接暴力求解.可以注意到因为点都是排好序的,所以两边当中的点的距离>= abs(P[i].x - P[mid].x).那么如果这个距离已经大于我们当前找到的最优答案,显然就不需要再去计算一遍啦.那么我们再把那些还可能含

算法(第四版)C#题解&mdash;&mdash;1.4

写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 这一节内容可能会用到的库文件有 Measurement 和 TestCase,同样在 Github 上可以找到. 善用 Ctrl + F 查找题目. 习题&题解 1.4.1 题目 证明从 N 个数中取三个整数的不同组合总数为 N(N - 1)(N - 2) / 6. 解答 即为证明组合计算公式: C(N, 3) = N! / [

[题解+总结]20151015分治

1.前言 互测题第四弹——来自Cab的分治(也就意味着昨天就是我的了).感觉今天的题目质量很高的,涉及的知识很全面,虽然都是在分治的基础上.暴力全部没有打对,唉. 2.Color 栅栏涂漆 大概题意:给出n个高度为h[i]的栅栏,每次可以横着或竖着给一行或一列涂色,每个栅栏小格子只能被涂色一次,求最少要涂色多少次. 题解:二分.和NOIP2013的积木大赛非常相似,但是本题可以一列一列涂色,但是可以注意到,我们当且仅当目前处理的区域只存在一列时才需要一列涂色,所以差别并不大. 3.chebnea

[题解+总结]20151010

1.前言 又是绿书上的题目.这种画风感觉还是好些的,虽然都是远古时代的.今天题目感觉难度适中,但是太过于偏向动态规划了吧...还有搜索傻逼题乱入. 2.Sort 产品排序 大概题意:给出n个产品,每个产品有加工时间和冷却时间.现有两台加工机,每台加工机同一时间只能加工一个产品.产品加工完后就进入冷却时间.要求在尽可能短的时间内完成所有产品的所有工序,求最短时间. 题解: 动态规划.设存在两个产品x和y,y的冷却时间大于x,且x排在y之前.如果x和y是相邻的,可以发现在这种情况下完成时间是max{

JOI 2012 fish 题解

题目大意: 给你一个0/1/2序列Ai,每个值Ai有一个权值Pi.如果两个值的权值Pi和Pj满足Pi≥2Pj,那么Ai就会把Aj吔掉,也就是说Ai, Aj不能共存. 称Ai的一个子序列的特征三元组为(Sum0, Sum1, Sum2),其中Sump为子序列中的Ai=p的个数.当然这里要求所有值可以共存. 求:Ai的所有合法子序列的特征三元组的种类数目.1≤N≤200000. 这道题可谓是难题(对于我),同样是听完题解外加问人外加参考代码才回的,我们给个原题网址(日文版)戳一下http://www

poj 1106(半圆围绕圆心旋转能够覆盖平面内最多的点)

Transmitters Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4955   Accepted: 2624 Description In a wireless network with multiple transmitters sending on the same frequencies, it is often a requirement that signals don't overlap, or at

ZOJ Monthly,Feburary 2012 部分题解

题目链接:点击打开链接 ZOJ 3573 Under Attack 距离做这套题到写题解间隔比较久,题意有些忘了.. #include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cmath> #include <cstring> #include <queue> #include <set> #in

sgu100~199题解

老东西了..发上来吧.. Sgu题解系列  南开中学邹事成 100:A+B略 101:Domino 给n块多米诺骨牌,每张骨牌两端各有从1到6的一个数字,现在要把这些骨牌排成一列,使相邻的两块骨牌相对的面所写的数字一样. 可以把每一块多米诺骨牌想象成一条边,把面上写的数字抽象成点,比如一块骨牌正面写的1反面写的2就想象成连了一条从1到2的边,那么这就是求一条有重边的欧拉回路了,dfs一下即可. 102:Coprimes给定n求从1到n中与n互质的数的个数. 可以把n质因数分解后直接代入欧拉函数.

算法(第四版)C#题解&mdash;&mdash;1.2

写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 这一节内容可能会用到的库文件有 Geometry 和 Commercial,同样在 Github 上可以找到. 善用 Ctrl + F 查找题目. 习题 & 题解 练习(1.2.1~1.2.14) 1.2.1 题目 编写一个 Point2D 的用例,从命令行接受一个整数 N.在单位正方形中生成 N 个随机点,然后计算两点之间的最