P1182 数列分段 Section II

1|0P1182 数列分段 Section II

1|0再一次对位单杀18年的我

2018 0pts

#include<cctype> #include<cstdio> #include<algorithm> using std::sort; int n,a[100010],QZ_sum[100010],m,ans=-0x7fffffff,minn=0x7fffffff; inline int read(int &x){ x=0; char ch=0; bool sign=false; while(!isdigit(ch)){sign|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=x*10+(ch^48);ch=getchar();} x=sign?-x:x; } inline int max(int a,int b){ return a>b?a:b; } inline int min(int a,int b){ return a<b?a:b; } inline void out(int x){ if(x<0)putchar('-'),x=-x; if(x>9)out(x/10); putchar(x%10+'0'); } inline void dfs(int i,int num,int sum,int ans){ if(i==n+1){ if(num>=m){ minn=min(minn,ans); } return ; } int cmp=max(ans,sum); dfs(i+1,num+1,a[i+1],cmp); dfs(i+1,num,sum+a[i+1],ans); } int main(){ read(n);read(m); for(int i=1;i<=n;i++){ read(a[i]); } dfs(1,1,a[1],-0x7fffffff); dfs(1,0,a[1],-0x7fffffff); out(minn); return 0; }

最近复习二分,这题其实就是套板子,check函数也还算好实现,但是只拿了80pts。

80pts

#include<iostream> #include<algorithm> #define ll long long using namespace std; ll l, r, mid; int n, m; int a[100010]; bool check(int x) { int temp = 0, cnt = 0; for (int i = 1; i <= n; i++) { if (temp + a[i] > x) { cnt++; temp = a[i]; } else { temp += a[i]; } } cnt = (temp) ? cnt + 1 : cnt; return temp <= x && cnt <= m; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } l = 1, r = 1e9; int ans = 0; while(l <= r) { mid = l + ((r - l) >> 1); if (check(mid)) { ans = mid; r = mid - 1; } else { l = mid + 1; } } printf("%d", ans); return 0; }

百思不得其解,看了讨论区很多人和我一样,然后发现了问题。

l左区间不能从1或者0开始,因为二分答案查找的是数列分段和的最小值,而左区间从零开始则排除不了mid小于数列其中一个数的情况,而这种情况显然是不成立的,我的算法中也没有加入特判,因此最优解就是直接把l左区间设成数列中的最大值,防止出现数列和最大值比数列中其中一个数还小的情况

100pts

#include<iostream> #include<algorithm> #define ll long long using namespace std; ll l = 0, r, mid; int n, m; ll a[100010]; bool check(int x) { int temp = 0, cnt = 0; for (int i = 1; i <= n; i++) { if (temp + a[i] > x) { cnt++; temp = a[i]; } else { temp += a[i]; } } cnt = (temp) ? cnt + 1 : cnt; return temp <= x && cnt <= m; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); l = max(l,a[i]); } r = 1e9; int ans = 0; while(l <= r) { mid = l + ((r - l) >> 1); if (check(mid)) { ans = mid; r = mid - 1; } else { l = mid + 1; } } printf("%d", ans); return 0; }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/17789682.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示