Painting Fence题解
来源:互联网 发布:mac倍速看视频 编辑:程序博客网 时间:2024/05/01 13:55
codeforces里题目链接:http://codeforces.com/problemset/problem/448/C
要翻墙...
这道题一看题目,应该一开始就想到DP,然后复杂度O(n2),这个平方复杂度我就没去细想怎么实现了。
然后就是想有没有更好的方法,复杂度更低。
很容易能想到,如果某一列没有竖刷,那么必然被横刷,那么一定要从低处往高处都要横刷。所以如果整个区域有横刷,那么高度最矮的那一列一定要被完全横刷掉。
此时,这个区域除掉这些被横刷的这几行,上面的部分被分成好多堆。每一堆的求解跟原问题是一样的,所以可以分治(递归)求解。
上面这个方法就要不断找最小值,所以复杂度应该可以被压缩到nlog(n)。或者最小值不用找,直接快排一下,然后从小到大处理,复杂度nlog(n)。
nlog(n)的话,再考虑能否优化到O(n)。想到上面的log(n)花费花在求最小值上面,考虑是否有方法避免不求最小值,或者说,能否不按从小到大的顺序进行求解公式。
每一列,往左边数第一个小于它高度的位置记为index_left,往右边数第一个小于它高度的位置记为index_right。从而[index_left,index_right]可以看成一堆进行求解,而不对其它造成影响。 所以该题可以利用单调栈的思路来求解。
基本公式如下:
构建一个递增的单调栈,然后按公式进行求解,第一种情况,result赋给result_right,第二种,result赋给result_left
当然,上面只是基本公式,还有一些细节要处理才算严格正确。比如,相等高度的情况等等。
虽然代码中for循环里有while循环,但实际复杂度确实为O(n)。代码如下:
#include <stdio.h>#define mymaxsize 5001int myresult[mymaxsize]; //初始值为0int A[mymaxsize], index[mymaxsize]; //, index_right[mymaxsize]//, index_left[mymaxsize],index_right 记录右边第一个小于它的数的index index_left 记录左边第一个小于它的数的indexint result_left[mymaxsize], result_right[mymaxsize];//int same_num[mymaxsize];int n, i,tmp, num = 1;<pre name="code" class="cpp">int tmp1, tmp2;int main(){scanf("%d", &n);// A[0] = 0;// index[0] = 0;scanf("%d", &A[1]);index[1] = 1;// result_left[1] = 0;// index_left[1] = 0;for (i = 2; i <= n; ++i){scanf("%d", &tmp);if (A[num] >= tmp){num_left = num - 1;result_right[num] = 0;while (A[num_left] >= tmp){tmp1 = result_left[num] + result_right[num] + A[num] - A[num_left];tmp2 = i - index[num_left] - 1;if (tmp1 < tmp2) { result_right[num_left] = tmp1; }else { result_right[num_left] = tmp2; }--num;--num_left;}if (A[num]==tmp){result_left[num] = result_left[num] + result_right[num];}else{tmp1 = result_left[num] + result_right[num] + A[num] - tmp;tmp2 = i - index[num_left] - 1;A[num] = tmp;if (tmp1<tmp2) { result_left[num] = tmp1; }else { result_left[num] = tmp2; }}}else{A[++num] = tmp;result_left[num] = 0;}index[num] = i;}num_left = num - 1;result_right[num] = 0;while (num_left>=0){tmp1 = result_left[num] + result_right[num] + A[num] - A[num_left];tmp2 = i - index[num_left] - 1;if (tmp1 < tmp2) { result_right[num_left] = tmp1; }else { result_right[num_left] = tmp2; }--num; --num_left;}printf("%d", result_right[0]);return 0;}
代码中有些数组其实可以不用,直接优化掉,比如result_right其实可以不用数组,直接用个变量来代替即可,不过不想改了。
网上似乎有看到dp解法,不过没去看是否正确,直接先扔在这:
#include <iostream>using namespace std;int main() { int n; cin >> n; int a[n+1]; a[0] = 0; for (int i=1; i<=n; i++) cin >> a[i]; int dp[n+1][n+1]; for (int j=0; j<=n; j++) dp[n][j] = 0; for (int i=n-1; i>=0; i--) for (int j=0; j<=i; j++) { if (a[j] >= a[i+1]) dp[i][j] = dp[i+1][i+1]; //Already painted else { dp[i][j] = min( 1 + dp[i+1][j], a[i+1]-a[j] + dp[i+1][i+1]); } } cout << dp[0][0] << endl;}
这道题有大神指导建议,可以用 笛卡尔树...比较直观好理解。嗯,不懂...以后再看吧,以后千万别成永远了...
- Painting Fence题解
- 448C. Painting Fence
- C. Painting Fence codeforces
- cf448C. Painting Fence【dfs】
- codeforces C. Painting Fence
- Painting Fence[分治]
- CF 448C Painting Fence
- Codeforces 448 C. Painting Fence
- Codeforces 448C. Painting Fence
- #256 C. Painting Fence 分治
- CF448C Painting Fence(递归+贪心)
- CodeForces 448-C. Painting Fence
- CF 448C Painting Fence
- codeforces 448C Painting Fence
- CodeForces-448C Painting Fence
- Codeforces 448C Painting Fence
- codeforces 448C Painting Fence
- 【杂题】 codeforces 448C Painting Fence
- seq_file工作机制实例
- c# 面向对象之类与对象
- 解决 “invalid package Applications built with SDK 9.0 or later must be packaged as proper IPA files.”s
- java正则表达式学习
- swift_02_基础知识
- Painting Fence题解
- fgetc
- 我的
- Gale Shapely算法的实现
- 嵌入式linux相关知识
- nfs安装失败
- [Android基础]Spanned与SpannableString
- linux文件的访问权限和文件模式
- mysql 遇到utf8mb4插入异常