蛋糕分层
蛋糕店刚好有对应上、中、下三层的三类蛋糕,大家知道多层蛋糕一般都是上层最小,中层其次,下层最大,不然蛋糕就不漂亮了。在知道每一种蛋糕的体积的前提下有多少符合条件的方案。
看到这道题,就感觉是动态规划,题目不是说蛋糕层数的要求吗?可以从下往上的推,个人的第二个感觉是一道搜索题,然后就这么打着,样例过的,手推的数据也过的。没想到就QAQ了。
【暴力出奇迹】
爆0之后,试了一下暴力,把每一种情况都考虑一遍,选最优值,这样时间复杂度是O(n^2)的。至少还有点分(虽然我没提交,但我知道啊)。个人感觉就是不对。emm,我想复杂了。
其实计数就是暴力的优化,读入把数字存入下标(万幸没有负数,哈哈)。数据卡的刚刚好。然后与暴力一样,不停地从上往下(只希望不要挂了),找最优值。啊,果然对了(AC)。这相当于是正解了吧。
先附上代码:(此代码,不要copy谢谢)
#include<bits/stdc++.h> // 万能头 using namespace std; // 空间定义 long long n,m,k,x,a[3939],b[3939],c[3939],maxn1,maxn2,maxn3,ans,a1[514514];//定义变量 int main() { //开始疯狂的操作 cin>>n>>m>>k; // 读入这些值 for(int i=1; i<=n; i++) { cin>>x; //读入 a[x]++; // 放入下标 maxn1=max(maxn1,x);//取最大值 } for(int i=1; i<=m; i++) { cin>>x; // 读入 b[x]++; // 放入下标 maxn2=max(maxn2,x); // 取最大值 } for(int i=1; i<=k; i++) { cin>>x; // 读入 c[x]++; // 放入下标 maxn3=max(maxn3,x); // 取最大值 } for(int i=1; i<=max(maxn3,maxn2); i++) c[i]=c[i-1]+c[i]; // 前缀处理 ,类似 dp for(int i=1; i<=max(maxn1+1,maxn2+1); i++) a1[i]=a1[i-1]+a[i-1]; // 前缀处理 ,类似dp for(int i=1; i<=maxn2; i++) ans+=(c[maxn3]-c[i])*b[i]*a1[i]; // 不停累积最优值 cout<<ans<<endl; // 输入 return 0; // 好习惯,别忘记了 }//End;
老师后来讲了这道题目,原来正解是二分,我恍然大悟(我那个时候为啥没有想到呢?)。
我知道你们对二分有点糊涂。
我来给你们讲一讲。
【二分】
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
二分查找对这道题没有用,我们解决这道题的话,要用二分答案。
【定义】
二分答案与二分查找类似,即对有着单调性的答案进行二分,大多数情况下用于求解满足某种条件下的最大(小)值。
- 何时可以使用“二分答案”
不是任何题目都适合使用“二分答案”的,我Sam观察到一般有以下的一些特征:
- A. 候选答案必须是离散的 ,且已知答案的范围是:[最小值min, 最大值max] (连续区间上不能进行二分操作)
- B. 候选答案在区间[min,max]上某种属性一类一类的排列 (这样就能在此属性上进行二分操作 ),各个类别不交错混杂
【模板说明】
一定要先排序。
可以把答案看成key , 一旦当前这个序列中的数(我是根据从小到大排序的)大于key ,则右端点(r)要等于中间值(我取中间值为(l+r)>> 1).否则就取左端点(l)要等于中间值。
从大到小同理.
【二分模板代码】(不同人写法不同)(这是我的模板)
int check(int key){ int l = 1,r = n; int mid; while(l<=r){ mid = (l+r) >> 1; if(key > a[mid]) l = mid+1; else if(key < a[mid])r = mid-1; else return 1; } return 0; }
介绍算法结束!
【将二分融入题目之中】
二分答案的使用可以在查找蛋糕的最优值时候使用。
其他一样。
代码就不放了。自己思考。。。。
End!