博客要写的整洁。气质是修炼不来的啊,体现在方方面面。
当代码越来越长的时候,当你又需要这样特判那样特判的时候……
你几乎已经错了。_(:з」∠)_
再改改不出来只能说之前想出的算法不适合吧……博客写工整一点
【二分】
最后想拿到的肯定是m=cnt&&rec=mid的,但是这个并不需要特判返回。
r<l的时候循环几乎已经退出了呀,我们需要的ans
emmm...错了一天 每次都有新的错法
啊~ 如果一个题想要二分要满足二分性的。
就是说,一长串,一半可以,另一半不行,我们二分的是那个分界线
可以的是满足题意,但是多了,不可以的就是真的不可以。
我在上个题目“数的坐标、扔石子”中的,前面不行后面不行中间去分吧,的解法,其实充其量只是一个枚举和缩小范围的界限而已。要理解二分的本质,即是就是是,不是就是不是,不要这样模棱两可。
本题要二分的不是那个最大值,而是在满足多少的前提下可以分成恰好m块。
至于细节,如果分成了2块(题目要求是3块)那么一定可以拆成3块,只是没拆的问题。即2是满足条件的那一方,2的话就是分块数量太少,因为最大值太大。
由此。题目中,右边(上面)是可行的,下面(左边)是不可行的,相应的二分程序也要改。
在抽同学二分模板中,cmp判断为真(条件可行)时才更新。一并更改便好。
恭喜我在抽同学的疯……狂提示下终于会了一点点二分。
他说这个很简单的,代码肯定不超过20行。我。。
最后写成这样还行吧-、- (过程要理解,上面边界是啥,下面边界是啥。(⊙_⊙))
#include<algorithm>
#include<vector>
#include<iostream>
#include<queue>
#include<stdio.h>
using namespace std;
int a[100005];
int n, m;
int cmp(int mid) {
int temp = 0; int cnt = 0;
for (int i = 1; i <= n; i++) {
if (temp + a[i] <= mid)temp = temp + a[i];
else if (temp + a[i]>mid){
cnt++;
temp = a[i];
}
}if (temp != 0)cnt++;
if (cnt>m)return 0;
return 1;
}
int main() {
cin >> n >> m;
int kkk = 0;
int sum = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum += a[i];
kkk = max(kkk, a[i]);
}
int l = kkk; int r = sum;int ans = 0;
while (l <= r) {
int mid = (l + r) / 2;
int xxx = cmp(mid);
if (xxx == 1){
r = mid - 1;
ans = mid;
}
else l = mid + 1;
}
cout << ans << endl;
return 0;
}
【动态规划】
前面做的。
(1)dp[0][0]=1
(2)在任何情况停下来都是最优解法
(3)此种情况可由正好两种情况推理而来/ 有两种可以促使它拿到今天的结果
(4)二维状态下坐标表示的是什么
如本题中dp[i][j]即第i秒在位置j处。想出了这一点继续推理也不复杂了
***记忆化搜索。
若更新过记录肯定不等于0,直接返回即可。【否则每次访问到都需要重新递归!!!!】
简单的一小句话救了TLE的命。
30*30的范围啊,,,