题解 P2884 【[USACO07MAR]每月的费用Monthly Expense】

xzyxzy

2017-07-03 11:10:14

Solution

难得的一次过的题 这道题是典型的二分答案加贪心策略(求最大值(最大fajo月的预算)的最小值): 先找到答案区间(在每个月的最大值和所有月的总和之间) 然后利用二分查找答案 精髓是check函数(详细过程注释已经讲明白了) 注意的是第一次查找到的解不一定是最优解,所以要定义ans来存储最优解 最后输出就好了 ```cpp #include<iostream> #include<cstdio> #include<cstdlib> using namespace std; int n,m,a[100001];//n天,m组,a[i]表示第i天的钱 int read()//读入优化 { char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); int h=0; while(ch>='0'&&ch<='9') { h=h*10+ch-48; ch=getchar(); } return h; } int check(int max1),q[100001]; int main()//求最大的最小值 { n=read(); m=read(); int l=0,r=0,ans; for(int i=1;i<=n;i++) { a[i]=read(); q[i]=q[i-1]+a[i];//定义前缀和 l=l>a[i]?l:a[i];//答案左区间应为最大的一个月 r+=a[i];//答案右区间应为每个月经费之和 } while(l<=r) { int mid=(l+r)/2,k=check(mid); if(k==1)//如果满足条件了,就记录此时的解(此时的解一定比之前查找到的更优,因为如果查到了解,就会在数值更大的区间内寻解) { ans=mid; r=mid-1;//在数值更大的区间内寻解 } else l=mid+1;//在数值更小的区间内寻解 } cout<<ans; return 0; } int check(int max1)//max1:一个fajo月(财政周期)的总经费的最大值 { int s,f; int tot=1;//表示划分的财政周期数 for(s=1;s<=n;s=f)//枚举起始月 { for(f=s+1;f<=n;f++)//枚举结束月 { if(q[f]-q[s-1]<=max1) continue;//如果这个周期内总额没超过查找到的答案,就继续加上下一个月 else//超过了就再加一个fajo月(贪心策略) { tot++;//新增一个fajo月 break;//再次枚举起始月 } } } if(tot<=m) return 1;//满足条件返回1 else return 0; } ```