链接:http://codeforces.com/contest/1118
来源:Codeforces
文章目录
- A. Water Buying
- B. Tanya and Candies(前缀和)
- D1. Coffee and Coursework (Easy version)(贪心)
- D2. Coffee and Coursework (Hard Version)(二分)
A. Water Buying
题意:用最小的花费买到刚好合适的东西.我们可以求出两种方案的花费,最后输出最小的即可.
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#define pi 3.1415926
#define mod 1000000007
#include<algorithm>
using namespace std;typedef long long LL;
const int Max_n=100005;
LL a[Max_n];int main(){int t;scanf("%d",&t);while(t--){LL n,a,b;scanf("%lld%lld%lld",&n,&a,&b);LL res,res1;if(n&1) res=a+(n-1)/2*b;else res=n/2*b;res1=n*a;printf("%lld\n",res>res1?res1:res);} return 0;
}
B. Tanya and Candies(前缀和)
题意:给你一个数组,删除其中一个元素,剩下的元素奇数位和偶数位的元素和相等,问这样的元素有多少个.我们可以用两个数组分别维护奇数位和偶数位的前缀和,当我们将某一个元素删除时,前面的不变,后面的位置奇偶互换.此时奇数和就是:sum1[i-1]+sum2[n]-sum[i](sum保存的分别是奇数和与偶数和),偶数和就是:sum2[i-1]+sum1[n]-sum1[n]-sum1[i]
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;typedef long long LL;
const int Max_n=200005;
int sum1[Max_n],sum2[Max_n],a[Max_n];int main() {int n;scanf("%d",&n);for(int i=1;i<=n;++i){scanf("%d",&a[i]);if(i&1){sum1[i]=sum1[i-1]+a[i];//奇数和sum2[i]=sum2[i-1];//偶数和}else{sum1[i]=sum1[i-1];sum2[i]=sum2[i-1]+a[i];}}int ans=0;for(int i=1;i<=n;++i){int sumj,sumo;sumo=sum2[i-1]+sum1[n]-sum1[i];sumj=sum1[i-1]+sum2[n]-sum2[i];if(sumj==sumo) ans++;}printf("%d\n",ans);return 0;
}
D1. Coffee and Coursework (Easy version)(贪心)
C. Magic Ship(二分天数):https://blog.csdn.net/qq_42217376/article/details/87895706
题意:有一个作业需要写m页,你有很多杯咖啡(一组数据),数值就代表喝一杯咖啡能够写多少页作业,在某一天你可以选择喝任意杯咖啡,但是当天的第一杯咖啡的贡献值是max(0,a1),第二杯就变成了max(0,a2-1),第三杯是max(0,a3-2),贡献值依次类推,让我们求最少多少天可以完成这些作业.上次写船那道题有一个奇特的想法那就是二分天数来找到最优解.这里我们可以枚举天数来找到最优解.(二分方法见下题.)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;typedef long long LL;
const int Max_n=200005;
int a[Max_n];int main() {int n,m,sum=0;scanf("%d%d",&n,&m);for(int i=1;i<=n;++i){scanf("%d",&a[i]);sum+=a[i];}if(sum<m){printf("-1\n");return 0;}sort(a+1,a+n+1,greater<int>());for(int days=1;days<=n;++days){//枚举天数int ans=0,cnt=0,b=0;for(int i=1;i<=n;i++){ans+=(a[i]-cnt);//假设我们当前有两天,我们把数组分成2组(贪心的规则去分组),计算出每组的和,最后找到最合适的天数.if(i%days==0) cnt++;if(ans>=m){b=1;break;}}if(b){printf("%d\n",days);break;}}return 0;
}
D2. Coffee and Coursework (Hard Version)(二分)
题意同上题相同,只不过这里数据范围变了,我们没办法在使用枚举来求解这道题,此时就用到二分天数来求解.
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;typedef long long LL;
const int Max_n=200005;
int a[Max_n],m,n;bool check(int mid){LL sum=0;for(int i=0,days=0;i<n;i++){sum+=max(0,a[i]-days);if((i+1)%mid==0) days++;}return sum>=m;
}int main() {scanf("%d%d",&n,&m);for(int i=0;i<n;++i)scanf("%d",&a[i]);sort(a,a+n,greater<int>());int l=1,r=Max_n,days=0;while(l<=r){int mid=l+((r-l)>>1);if(check(mid)){r=mid-1;days=mid;}else l=mid+1;}printf("%d\n",days?days:-1);return 0;
}