牛客团队赛50&CF#664(Div2)
作者:互联网
牛客团队赛50
A.Rental Service
题目:https://ac.nowcoder.com/acm/contest/6306/A
题解:牛有两种卖法:一个是卖奶,一个是租赁,比较二者哪个获利最多。
一道典型的贪心问题。
1.留下产奶量多的奶牛;
2.卖牛奶先卖给出价高的商铺;
3.把奶牛租给出价高的邻居。
我们按产奶量从多到少排序,按商铺价格从高到低排序,按出租的价格从高到低排序。
这里用到一个前缀和数组,来计算奶牛租赁的。
我们枚举第一头奶牛卖奶,其余奶牛租赁的最大价格,然后依次枚举,取其最大即可。注意代码中的:ans=max(ans,num+c[min(n-i,r)]);c为前缀和数组表示剩余n-i头奶牛租赁的最大价格
#include<iostream> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const ll N=100010; ll n,m,r; ll a[N],c[N]; ll ans,sum; struct node { ll q,p; }b[N]; bool cmp(node a,node b) { if(a.p!=b.p) return a.p>b.p; else return a.q>b.q; } bool cmp2(int a,int b) { return a>b; } int main() { ll i,j,k; ll flag=0; cin>>n>>m>>r; for(i=1;i<=n;i++) { cin>>a[i]; } sort(a+1,a+n+1,cmp2); for(i=0;i<m;i++) cin>>b[i].q>>b[i].p; sort(b,b+m,cmp); for(i=1;i<=r;i++) cin>>c[i]; sort(c+1,c+r+1,cmp2); for(i=1;i<=r;i++) c[i]+=c[i-1]; ll num=0; j=0; for(i=1;i<=n;i++) { while(j<m&&a[i]>=b[j].q) { a[i]-=b[j].q; num+=b[j].p*b[j].q; j++; } if(j<m) { b[j].q-=a[i]; num+=a[i]*b[j].p; } //前缀和数组模拟最大值,看有几个卖奶,几个租赁 ans=max(ans,num+c[min(n-i,r)]); } cout<<ans<<endl; return 0; }
H:Cow Coupons
题目:https://ac.nowcoder.com/acm/contest/6306/H
解法:也是一道谈心题,可从两方面入手:优惠券足够,优惠券不够
①优惠足够,就看钱数,按优惠后的价格从低到高进行购买
②优惠券不够,先按照优惠后的价格从低到高进行购买,买完后标记上,直到优惠券不够了钱还够,或者优惠券够钱不够了。
优惠券够钱不够,则直接输出;优惠券不够了钱够,就将数组按照原来的价格从低到高排序,便利购买时已标记过的不购买,计算直到钱不够为止。
代码:
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N=50010; struct node { ll p,c; bool flag; }a[N]; bool cmp1(node a,node b) { if(a.c!=b.c) return a.c<b.c; else return a.p>b.p; } bool cmp2(node a,node b) { return a.p<b.p; } int main() { ll i,j,n,k,m; ll ans=0; cin>>n>>k>>m; for(i=0;i<n;i++) { cin>>a[i].p>>a[i].c; a[i].flag=false; } sort(a,a+n,cmp1); if(k>=n) { for(i=0;i<n;i++) { if(m>=a[i].c) { m-=a[i].c; ans++; } else break; } cout<<ans<<endl; } else { bool flag=false; for(i=0;i<n;i++) { if(m>=a[i].c&&k>0) { m-=a[i].c; a[i].flag=true; k--; ans++; } if(k==0) break; if(m<a[i].c) { flag=true; break; } } if(flag==true) cout<<ans<<endl; else { sort(a,a+n,cmp2); for(i=0;i<n;i++) { if(a[i].flag==false) { if(m>=a[i].p) { m-=a[i].p; ans++; } else break; } } cout<<ans<<endl; } } return 0; }
J.Haybale Stacking
题目:https://ac.nowcoder.com/acm/contest/6306/J
题解:一道差分题。根据【l,r】,在这个区间每次都加1,因此设计一个差分数组d[N],他表示d[i]=a[i]-a[i-1],因此,每次给一段范围,
就让d[l]++,d[r+1]--。这样用0(1)的操作解决,之后在遍历a数组,a[i]=a[i-1]+d[i];得到最终的a数组,然后输出数组的中间数a[n/2+1]
代码:
#include<cstdio> #include<algorithm> #define MAXN 1000005 using namespace std; int a[MAXN],d[MAXN]; int n,p; int main(){ scanf("%d%d",&n,&p); while(p--){ int l,r; scanf("%d%d",&l,&r); d[l]++,d[r+1]--; } for(int i=1;i<=n;i++){ a[i]=a[i-1]+d[i]; } sort(a+1,a+n+1); printf("%d\n",a[n/2+1]); return 0; }
CF
A. Boboniu Likes to Color Balls
题目:https://codeforces.com/contest/1395/problem/A
题解:要想保证他为回文串,满足要求的是:
r%2+g%2+b%2+w%2<=1,意思是奇数个为1个情况
r&&g&&b&&(r%2+g%2+b%2+w%2>=3),奇数个为3个或者4个,并且r,g,b都得大于0,因为需要一次变化才能将其变成回文串,因此至少他们三个得大于0.
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<cstring> using namespace std; typedef long long ll; int main() { ll t,i,j,r,g,b,w; cin>>t; for(i=0;i<t;i++) { cin>>r>>g>>b>>w; if(r%2+g%2+b%2+w%2<=1||(r&&g&&b&&(r%2+g%2+b%2+w%2>=3))) cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }
B. Boboniu Plays Chess
题目:https://codeforces.com/contest/1395/problem/B
题解:从初始位置开始,确定一条唯一的遍历路线即可。
我的路线是:先从他的位置开始遍历其右边的位置,一直到边缘,然后再开始从他的左边开始遍历到左边缘,然后向上遍历,在向下遍历。很简单的
代码:
#include<iostream> using namespace std; const int N=110; int sx,sy; int main() { int i,j,n,m,k; cin>>n>>m>>sx>>sy; for(i=sy;i<=m;i++) cout<<sx<<" "<<i<<endl; for(i=sy-1;i>=1;i--) cout<<sx<<" "<<i<<endl; k=sx-1; int flag=0; while(k>=1) { if(flag==0) { for(i=1;i<=m;i++) cout<<k<<" "<<i<<endl; flag=1; k--; } else { for(i=m;i>=1;i--) cout<<k<<" "<<i<<endl; flag=0; k--; } } k=sx+1; while(k<=n) { if(flag==0) { for(i=1;i<=m;i++) cout<<k<<" "<<i<<endl; flag=1; k++; } else { for(i=m;i>=1;i--) cout<<k<<" "<<i<<endl; flag=0; k++; } } return 0; }
C. Boboniu and Bit Operations
题目:https://codeforces.com/contest/1395/problem/C
题解:一开始想的是用map数组来尽可能的收集相同的比a[i]本身要小的数,结果第三个样例都没过,然后知道这样没依据,行不通
然后看K的数据范围试2^9,n和m是200,枚举k,复杂度为O(knm),最大是2*10^8次方,还是可以接受的
因此枚举k,然后判断整个k能否于a[i]&b[j]进行或运算,并且等于k,如果可以遍历整个a数组,那么k就是最终的答案。
代码:
#include <cmath> #include <cstdio> #include <cstring> #include<iostream> using namespace std; int n, m, a[205], b[205]; int main() { int i,j,k; cin>>n>>m; for(i=0;i<n;i++) cin>>a[i]; for(i=0;i<m;i++) cin>>b[i]; for(k=0;k<=(1<<9);k++) { bool f=false; for(i=0;i<n;i++) { bool flag=false; for(j=0;j<m;j++) { if((k|(a[i]&b[j]))==k) { flag=true; break; } } if(flag==false) { f=true; break; } } if(f==false) { cout<<k<<endl; break; } } return 0; }
D. Boboniu Chats with Du
题目:https://codeforces.com/contest/1395/problem/D
题解:对于这个,我们采取贪心的思想,将大于的分为一组,小于的分为一组,然后按从大到小排序。
构造前缀和数组,然后我们的思想是,大于的那一组出现一次就要占去d+1个天数,实则不是,可以将其放到最后,那么就会只站一天,因此我们要充分的利用最后一天。
因此只要枚举从0~len1天,a中可以出现的个数,剩余的就是b中个数,然后取最大。
务必要注意一点:判断k>n,否则会导致数组下标不在范围内。
代码:
#include<iostream> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N=1e5+10; ll n,m,d; ll a[N],b[N]; ll pra[N],prb[N]; bool cmp(ll a,ll b) { return a>b; } ll ans; int main() { ll i,j,x; ll len1=0,len2=0; cin>>n>>d>>m; for(i=1;i<=n;i++) { cin>>x; if(x>m) a[++len1]=x; else b[++len2]=x; } sort(a+1,a+len1+1,cmp); sort(b+1,b+len2+1,cmp); for(i=1;i<=len1;i++) pra[i]=pra[i-1]+a[i]; for(i=1;i<=len2;i++) prb[i]=prb[i-1]+b[i]; ans=prb[len2]; for(i=1;i<=len1;i++) { int k=(i-1)*(d+1)+1; //不判断会导致数组超界 if(k>n) break; ll t=min(n-k,len2); ans=max(ans,pra[i]+prb[t]); } cout<<ans<<endl; return 0; }
标签:int,ll,664,50,long,CF,++,ans,include 来源: https://www.cnblogs.com/xiaofengzai/p/13495343.html