codeforces895A Pizza Seperation
2017-12-14 22:34
134 查看
Div2的T1出这个真的好吗…
思考余地很大的一道题。
来说说题意吧。有一个和为360的环形数列,将其分成两半使得差最小。
一个直观的做法是滚动n次,然后我们可以预处理一个前缀和,并从前往后扫一遍,这样可以过掉这道题,复杂度是O(n2)的。但这个复杂度显然不能让我们满意。
于是作者给出了一个很有趣的做法:
首先明确一点,对于一个环形数列来说,将之展开之后,分成两部分,一定有一部分是处于当前的展开之内的。
比如说:
170 30 150 10
这样最小的差出现在情况170+10和30+150上,在该情况下,尽管170和10是分开的,但是30和150仍然是连续的一段。
由于如果一段区间是确定的,比如t,那么另外部分的和就是360−t,所以两部分的差值就是|2t−360|,换言之,180就是我们期望达到的该区间和,因为此时差值为0。
所以可以以此为基础来设计贪心策略:
移动区间的右端点,每次移动求出最值
当区间和>=180时,移动左端点直到再次<180,当然每次移动也要求出最值
有些类似滑动窗口的做法,由于每个元素最多有1次进入左端点和右端点,所以复杂度是O(n)的。
之所以这道题可玩性很强,是因为稍微改一改条件,就可以有很多值得思考之处。
我们得到一个结论:对于和为n的环形数组分两段,以n>>1为基准贪心是一种明智的选择。
如果不是必须连续,分成两个集合,又如何呢?
然后我在查资料的时候,看到了一个很有趣的博客:
http://blog.csdn.net/htq__/article/details/50925205
其思路给了我一个提示:由于我们想要达到n>>1这个值,其实这个是等价于0-1背包的,也就是从n个元素中选取n个和不超过n>>1并且和最大的,也就是dp[i]=max(dp[i],dp[i−a[i]])+a[i]
还有可以展开思考的余地。如果是分成k段区间使得和的方差最小,又有什么做法呢?……
思考余地很大的一道题。
来说说题意吧。有一个和为360的环形数列,将其分成两半使得差最小。
一个直观的做法是滚动n次,然后我们可以预处理一个前缀和,并从前往后扫一遍,这样可以过掉这道题,复杂度是O(n2)的。但这个复杂度显然不能让我们满意。
于是作者给出了一个很有趣的做法:
首先明确一点,对于一个环形数列来说,将之展开之后,分成两部分,一定有一部分是处于当前的展开之内的。
比如说:
170 30 150 10
这样最小的差出现在情况170+10和30+150上,在该情况下,尽管170和10是分开的,但是30和150仍然是连续的一段。
由于如果一段区间是确定的,比如t,那么另外部分的和就是360−t,所以两部分的差值就是|2t−360|,换言之,180就是我们期望达到的该区间和,因为此时差值为0。
所以可以以此为基础来设计贪心策略:
移动区间的右端点,每次移动求出最值
当区间和>=180时,移动左端点直到再次<180,当然每次移动也要求出最值
有些类似滑动窗口的做法,由于每个元素最多有1次进入左端点和右端点,所以复杂度是O(n)的。
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; int n, a[370], sum, ans = 0x3fffff; int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); cin>>n; for(int i = 1; i <= n; ++i) cin>>a[i]; int l = 1 , r = 1; while(r <= n) { //cout<<"r"<<r<<endl; sum += a[r]; while(sum >= 180) { //cout<<"l"<<l<<" "; ans = min(ans, abs(360 - 2 * sum)); sum -= a[l]; l++; } ans = min(ans, abs(360 - 2 * sum)); r++; } cout<<ans<<endl; }
之所以这道题可玩性很强,是因为稍微改一改条件,就可以有很多值得思考之处。
我们得到一个结论:对于和为n的环形数组分两段,以n>>1为基准贪心是一种明智的选择。
如果不是必须连续,分成两个集合,又如何呢?
然后我在查资料的时候,看到了一个很有趣的博客:
http://blog.csdn.net/htq__/article/details/50925205
其思路给了我一个提示:由于我们想要达到n>>1这个值,其实这个是等价于0-1背包的,也就是从n个元素中选取n个和不超过n>>1并且和最大的,也就是dp[i]=max(dp[i],dp[i−a[i]])+a[i]
还有可以展开思考的余地。如果是分成k段区间使得和的方差最小,又有什么做法呢?……
相关文章推荐
- jQuery实现仿微软首页感应鼠标变化滑动窗口效果
- hydra暴力破解
- PHP 算法学习之二分法
- 用fail2ban阻止SSH和VSFTP暴力破解密码
- TCP/IP滑动窗口
- 五条强化 SSH 安全的建议
- 1.一些 贪心算法 的简单思维题:
- UVa 10394-Twin Primes
- CodeForces 797C
- gym101194 china final Problem D. Ice Cream Tower(二分)
- HDU 4310
- 贪心算法——字典序最小问题
- 贪心算法——区间调度问题
- 最终还是水过去的解题报告
- 2015BJOI day1第三题 糖果candy
- 排座椅
- 守望者的逃离
- luogu P1969积木大赛(NOIP 2013 TG)
- Codeforces Round #197 (Div. 2)
- Codeforces Round #198 (Div. 1)