Codeforces Round #552 Div. 3

题目链接:戳我

前两题是littlesun_wl小可爱写的qwqwq

A

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define MAXN 100010
#define INF 0x3f3f3f3f
using namespace std;
int a[MAXN];
int main()
{
	for(int i=1;i<=4;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+5);
	int x=(a[1]+a[2]-a[3])/2;
	int y=(a[2]+a[3]-a[1])/2;
	int z=(a[1]+a[3]-a[2])/2;
	printf("%d %d %d",x,y,z);
	return 0;
 } 

B

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define MAXN 1000
#define INF 0x3f3f3f3f
using namespace std;
int G[MAXN];
int sign[MAXN];
int cnt;
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&G[i]);
	}
	int mx=0;int mn=INF;
	for(int i=1;i<=n;i++)
	{
		sign[G[i]]++;
		mx=max(mx,G[i]);
		mn=min(mn,G[i]);
	}
	int k1=(mx-mn)/2;
	int k2=mx-mn;
//	printf("mn=%d,mx=%d,k=%d",mn,mx,k);
	int num;
	for(int i=1;i<=100;i++)
	{
		if(sign[i]!=0) cnt++;
		if(G[i]!=mx&&G[i]!=mn&&G[i]!=0) num=G[i];
		
	}
//	printf("%d",cnt);
	if(n==1||cnt==1)
	{
		printf("0");
		return 0;
	}
	if(cnt!=2&&cnt!=3)
	{
		printf("-1");
		return 0;
	}
	else if(cnt==2)
	{
		if(k2%2==0)
		{
			printf("%d",k1);
			return 0;
		}
		else
		{
			printf("%d",k2);
			return 0;
		}
		
	}
	else if(cnt==3)
	{
		int a=mn+k1;
//		printf("a=%d",a);
		if(a==num&&k2%2==0)
		{
			printf("%d",k1);
			return 0;
		}
		else
		{
			printf("-1");
			return 0;
		}
	}
	return 0;
}

C

算出来有多少循环,然后处理一下边上的特殊情况即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define MAXN 1000010
using namespace std;
typedef long long ll;
const int INF=1e9+71017;
int n,ans,a[3];
int p[7]={0,0,1,2,0,2,1};
int c[3]={3,2,2};
int g[3];
int getans(int k)
{
	int t=INF;
	for(int i=0;i<3;i++) g[i]=a[i],t=min(t,a[i]/c[i]);
	for(int i=0;i<3;i++) g[i]-=c[i]*t;
	t=t*7;
	for(int i=k;i!=(k+6)%7;i=(i+1)%7)
	{
		if(!g[p[i]]) break;
		else t++,g[p[i]]--;
	}
	return t;
}
int main()
{
	#ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d",&a[0],&a[1],&a[2]);
	for(int i=0;i<7;i++)
		ans=max(ans,getans(i));
	printf("%d\n",ans);
	return 0; 
}

D

贪心
如果没有日光,显然是要先用能被恢复的。
如果有日光,分类讨论一下能被恢复的是否到达上限即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 200010
int n,a,b,ans;
int p[MAXN];
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d%d%d",&n,&a,&b);
    int aa=a,bb=b;
    for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    for(int i=1;i<=n;i++)
    {
        if(a==0&&b==0) break;
        if(p[i]==0)
        {
            if(b) b--;
            else a--;
        }
        else
        {
            if(b<bb)
            {
                if(a) a--,b++;
                else b--;
            } 
            else
            {
                if(b) b--;
                else a--;
            }
        }
        ans=i;
    }
    printf("%d\n",ans);
	return 0;
}

E

两个人在一个序列中交替选择,每次从值最大的位置开始选,左右分别拓展,拓展K位(如果没有的话就停止)。每次选择完之后序列会去掉选择的人。问最后原序列上每个位置的人是被谁选择的。
emmmm 上届为\(n^2\)的暴力当然是很好打的啦,如何优化复杂度呢?每次选择完之后,记录一下l,r两个数组,表示选择的人的左右区间,最右边的位置的l为最左边的位置,最左边的位置的r为最右边的位置。这样左右拓展K位的时候就可以避免重复访问已经选择过的人啦!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define MAXN 400010
using namespace std;
int n,cnt,maxx,k,op=1;
int a[MAXN],l[MAXN],r[MAXN],c[MAXN];
struct Node
{   
    int pos,sum;
    friend bool operator < (Node x,Node y){return x.sum<y.sum;}
};
priority_queue<Node>q;
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) 
        scanf("%d",&a[i]),l[i]=r[i]=i,q.push((Node){i,a[i]});
    maxx=n;
    while(!q.empty())
    {
        int cur_pos=q.top().pos;
        c[cur_pos]=op;
        int ll=cur_pos-1;
        for(int i=1;i<=k;i++)
        {
            while(c[ll]&&ll>0) ll=l[ll]-1;
            if(ll<=0) break;
            c[ll]=op;
        }
        int rr=cur_pos+1;
        for(int i=1;i<=k;i++)
        {
            while(c[rr]&&rr<=n) rr=r[rr]+1;
            if(rr<=0) break;
            c[rr]=op;
        }
        r[ll]=rr;
        l[rr]=ll;
        op=3-op;
        while(!q.empty())
        {
            if(c[q.top().pos])q.pop();
            else break;
        }
    }
    for(int i=1;i<=n;i++) printf("%d",c[i]);puts("");
    return 0;
}

F

题意是给你一些东西,每个东西都有价值。还有一些优惠条件,形式为“每买n个物品,前m便宜的物品免费”。问如果买k个东西,最少需要多少钱?
因为涉及到前m便宜的东西免费,所以肯定要先从小到大排序。然后我们从小到大取,用优惠条件去凑k个。
这时候。。。就想到了动态规划。
我们设\(dp[i]\)表示排序之后,买i件物品最少需要多少钱。然后记录一个前缀和。
因为k比较小,所以我们只要开一个桶,\(pay[i]\)表示买i个东西,最多可以免费的物品个数。
然后\(k^2\)转移即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define MAXN 200010
int n,m,k;
int sum[MAXN],cost[MAXN],pay[MAXN],dp[MAXN];
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) scanf("%d",&cost[i]);
    for(int i=1;i<=m;i++) 
    {
        int cur1,cur2;
        scanf("%d%d",&cur1,&cur2);
        if(cur1>k) continue;
        if(pay[cur1]&&cur2>pay[cur1]) pay[cur1]=cur2;
        if(pay[cur1]==0) pay[cur1]=cur2; 
    }
    sort(&cost[1],&cost[n+1]);
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+cost[i];
    memset(dp,0x3f,sizeof(dp));
    dp[0]=0;
    for(int i=0;i<=k;i++)
    {
        for(int j=1;j<=k;j++)
        {
            if(pay[j]==0) continue;
            dp[i+j]=min(dp[i+j],dp[i]+sum[i+j]-sum[i+pay[j]]);
        }
        dp[i+1]=min(dp[i+1],dp[i]+sum[i+1]-sum[i]);
    }
    printf("%d\n",dp[k]);
	return 0;
}

G

题意是给你一些数,求两个位置,使得这两个位置上面的数的LCM全局最小。
因为LCM是两个数的乘积除以GCD,所以我们考虑枚举GCD,开一个桶记录每个数出现的位置,从GCD向上一路查询,找最小的前两个即可。
怎么说呢,一般这个数据范围都是枚举约数的做法吧!

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define MAXN 1000010
using namespace std;
int n,pos1,pos2;
int a[MAXN],pos[10000010];
long long ans=0x3f3f3f3f3f3f3f3f;
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		if(pos[a[i]])
		{
			if(a[i]<ans)
				ans=1ll*a[i],pos1=pos[a[i]],pos2=i;
		}
		else pos[a[i]]=i;
	}
	for(int i=1;i<=10000000;i++)
	{
		if(i>ans) break;
		int ll=0;
		for(int j=i;j<=10000000;j+=i)
		{
			if(pos[j]==0) continue;
			if(!ll) ll=j;
			else
			{
				long long cur_ans=1ll*j*ll/i;
				if(cur_ans<ans) 
				{ans=cur_ans,pos1=pos[ll],pos2=pos[j];break;}
			}
			
		}
	}
	if(pos1>pos2) swap(pos1,pos2);
		printf("%d %d\n",pos1,pos2);
	return 0;
}
posted @ 2019-04-28 11:12  风浔凌  阅读(94)  评论(0编辑  收藏  举报