Codeforces Round #218 (Div. 2)

这场开局不顺。。A题都不会做。。。B题一直不知道他只能用2,3,5。。。然后就拙计。好在最后4题都是1A没有fst勉强前50。。E题最后十分钟写了乱交也没A,事实上有很多bug赛后才A的。


C:

题意:有三种材料做汉堡。他手头上已经有一些材料,同时他有一定的现金可以去买材料。求最多能做几个汉堡。


思路:二分答案


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;

#define N  100010
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a)   memset(x,a,sizeof(x))
typedef long long    ll;
typedef pair<int,int> PI;
const int INF    = 0x3fffffff;
const int MOD    = 100000007;
const double EPS = 1e-7;

char s[N];
int cnt[16];
int p[16];
int need[16];
ll money;

bool check(ll num)
{
	ll tot=0;
	for(int i=0;i<3;i++){
		tot+=1ll*max(num*need[i]-cnt[i],0ll)*p[i];
	}
	return tot<=money;
}

int main()
{
	int a,b;
	scanf("%s",s);
	for(int i=0;i<3;i++) scanf("%d",&cnt[i]);
	for(int i=0;i<3;i++) scanf("%d",&p[i]);
	for(int i=0;s[i];i++){
		if(s[i]=='B') need[0]++;
		else if(s[i]=='S') need[1]++;
		else need[2]++;
	}
	scanf("%I64d",&money);

	ll l=0, r=money+1000;

	while(l<r){
		ll mid=(l+r)>>1;
		if(check(mid)) l=mid+1;
		else r=mid;
	}
	printf("%I64d\n",r-1);
    return 0;
}


D:

题意:给你一层一层的水盆,从上往下,水满了会流到下面的水盆里。可以给某个水盆加水,同时也会询问某个水盆当前水的体积。注意一下,水盆的体积不一定递增,即便下面的水盆比上面的小,也能接到上面流下来的水。


思路:如果某个水盆装满了,那上面流下的水只会经过它再流到下面没满的水盆里。所以我们可以用链表维护,把满的水盆删掉。每个点最多被删一次,复杂度O(n)


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;

#define N  200010
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a)   memset(x,a,sizeof(x))
typedef long long    ll;
typedef pair<int,int> PI;
const int INF    = 0x3fffffff;
const int MOD    = 100000007;
const double EPS = 1e-7;

int n,r[N];
bool vis[N];
ll vol[N],a[N],x;

void init()
{
	for(int i=1;i<=n;i++)
		r[i]=i+1;
	CLR(vis,true);
}
int next(int i)
{
	return vis[i] ? i : (r[i]=next(r[i]));
}
void erase(int s,int t)
{
	s=next(s);
	while(s<t){
		ll Min=min(vol[s],x);
		vol[s]-=Min;
		x-=Min;
		if(!vol[s]) vis[s]=false;
		else return ;
		if(!x) return ;
		s=next(r[s]);
	}
}

int main()
{
	int m;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%I64d",&vol[i]);
		a[i]=vol[i];
	}
	init();
	scanf("%d",&m);
	int op,p;
	while(m--){
		scanf("%d%d",&op,&p);
		if(op==1){
			scanf("%I64d",&x);
			erase(p,n+1);
		}else{
			printf("%I64d\n",a[p]-vol[p]);
		}
	}
    return 0;
}


E:


题意:n个站点,去掉一些,剩下k个站点。使得k个站点两两的距离和最小。


思路:排序后,答案显然是连续的k个站点。至于是哪连续k个,两个指针扫一下就好了,具体看代码。


比赛的时候排序完了,没有记录原始的位置,赛后才发现。。。


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;

#define N  300010
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a)   memset(x,a,sizeof(x))
typedef long long    ll;
typedef pair<int,int> PI;
const int INF    = 0x3fffffff;
const int MOD    = 100000007;
const double EPS = 1e-7;

pair<ll,int> a[N];

int main()
{
	int n,m;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%I64d",&a[i].first);
		a[i].second=i;
	}
	sort(a+1,a+n+1);
	scanf("%d",&m);
	ll ans=0,sum=0,l=1;
	for(int i=1;i<=m;i++){
		ans+=(i-1)*a[i].first-sum;
		sum+=a[i].first;
	}
	ll now=ans;
	for(int i=m+1,j=1;i<=n;i++,j++){
		sum-=a[j].first;
		now+=(m-1)*a[i].first-sum - (sum-(m-1)*a[j].first);
		if(now<ans){
			ans=now;
			l=j+1;
		}
		sum+=a[i].first;
	}
	for(int i=l;i<=l+m-1;i++) printf("%d ",a[i].second); puts("");
    return 0;
}


你可能感兴趣的:(codeforces)