赞
踩
刷点题~
1.二分+多路归并算法
对于每一个技能,我们把它看成一个等差数列,我们把所有可能都放到一个集合里,排个序,取前m个大即可,现在考虑优化,假如m不是很大,我们直接用优先队列即可,但是这里m很大,于是我们考虑二分,我们二分一下第m位选什么-x,那么大于X的>=m个,大于x的<m个,这里x就有二分性质,当我们确定x,那么对于每一个等差数列,我们可以用O(1)求出来,因此复杂度为nlogn。
下面是AC代码:
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long LL;
- const int N=100010;
- int n,m;
- int a[N],b[N];
- bool check(int mid){
- LL res=0;
- for(int i=0;i<n;i++){
- if(a[i]>=mid) res+=(a[i]-mid)/b[i]+1;
-
- }
- return res>=m;
- }
- int main(){
- cin>>n>>m;
- for(int i=0;i<n;i++) scanf("%d%d",&a[i],&b[i]);
- int l=0,r=1e6;
- while(l<r){
- int mid=(l+r+1)/2;
- if(check(mid)) l=mid;
- else r=mid-1;
- }
- LL res=0;
- LL cnt=0;
- for(int i=0;i<n;i++){
- if(a[i]>=r){
- int c=(a[i]-r)/b[i]+1;
- int end=a[i]-(c-1)*b[i];
- cnt+=c;//cnt计算了重复的,当它>m时减去多的R
- res+=(LL)(a[i]+end)*c/2;
- }
- }
- cout<<res-(cnt-m)*r;
- }
2.
对于每一个数据,我们求出来满足[A/V](下取整)=B的v的范围,然后取交集即可。
我们考虑一下A/V与V的函数图像:
因此就可以二分了,vmin=A/V<=B的最小的V,vmax=A/V<=B-1的最小的V-1(当然不用二分用公式也可)
下面是公式:
A/V在【B,B+1)内,转一下可得V为【A/B,A/(B+1))即可。
3.前缀和
我们看最终情况,它是中间一段是画的,旁边两端是被摧毁的,画的长度是n/2的上取整,事实上,我们可以取到任意的该长度的区间,如何证明?
首先,我们任取该长度的区间,我们大致做一下对称:
先看看奇数长度,对于第一步,我们先话中间空余的,以后哪一端是要坏的我们选那一段,这样子就可以了。
对于偶数长度,第一步任取接下来跟奇数一样即可。
因此问题就是求某一区间的最大和,这个用前缀和即可
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。