Diorvh

导航

【日记】12.27/【题解】CF Edu79

12.27

CF Edu79

A.New Year Garland

题意:有r,g,b个红绿蓝色气球,现问是否可以排成一列,使得没有两个相邻气球颜色相同。

思路:如果最大值>两个小数+1,就挂了。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define mid ((l+r)>>1)
const int M=1e5+20;
struct Task{
	int a,b,c;
	void init(){
		scanf("%d%d%d",&a,&b,&c);
	}
	void run(){
		init();
		int mx=max(a,max(b,c)),sum=a+b+c;
		if (mx>sum-mx+1)
			printf("No\n");
		else
			printf("Yes\n");
	}
}t;
int main(){
	int T;
	scanf("%d",&T);
	for(int i=1;i<=T;++i)
		t.run();
	return 0;
}

B.Verse For Santa

题意:有n个片段,每个片段需要a[i]分钟,一共有s分钟,必须从头开始按顺序念,但可以skip掉一个。问为了念出最多的片段,需要删掉哪一个?

思路:一万个假算法。其实很简单,先不skip,找到临界点,那么要么skip第一个念不完的,要么skip掉前面最大的,选最大的那个skip就行了。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define mid ((l+r)>>1)
const int M=1e5+20;
struct Task{
	int n,s,a[M];
	int mxp=0;
	void init(){
		mxp=0;
		scanf("%d%d",&n,&s);
		for(int i=1;i<=n;++i)
			scanf("%d",&a[i]);
		a[n+1]=0;
	}
	void run(){
		init();
		int p=1;
		while(p<=n&&a[p]<=s){
			s-=a[p];
			if (a[p]>a[mxp])
				mxp=p;
			++p;
		}
		if (p>n||n==1)
			printf("0\n");
		else{
			if (a[mxp]>a[p])
				printf("%d\n",mxp);
			else
				printf("%d\n",p);
		}
	}
}t;
int main(){
	int T;
	scanf("%d",&T);
	for(int i=1;i<=T;++i)
		t.run();
	return 0;
}

C.Stack of Presents

题意:有一堆礼物,从上到下编号依次为a1,a2,……an。现在要顺次拿b1,b2,……,bn的礼物,每次拿都需要消耗2k+1秒,k是目标礼物上面的礼物个数。但每次拿一个礼物之后,可以把上面的礼物按任意顺序排序。现在问按顺序拿出所有礼物的最小时间是多少。

思路:可以想到,如果当前礼物在之前已经被搬动过,那么拿这个礼物的时间就是1,因为上次搬动它的时候,你一定能有办法把它安排到拿它的时候恰好在最顶上。所以直接设置指针和vis数组,如果没被访问过就往后找,找的过程中把翻过的全都在vis里面记录一下即可。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define mid ((l+r)>>1)
#define db(x) cout<<#x<<":"<<x<<endl;
const int M=1e5+20;
struct Task{
	int n,m,a[M],b[M],vis[M];
	void init(){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i)
			scanf("%d",&a[i]),vis[i]=0;
		for(int i=1;i<=m;++i)
			scanf("%d",&b[i]);
	}
	void run(){
		init();
		LL ans=0;
		int p=1;
		for(int i=1;i<=m;++i){
			if (vis[b[i]])
				++ans;
			else{
				while(p<=n&&a[p]!=b[i])
					vis[a[p]]=1,++p;
				ans+=2*(p-i)+1;
			}
		}
		printf("%lld\n",ans);
	}
}t;
int main(){
	int T;
	scanf("%d",&T);
	for(int i=1;i<=T;++i)
		t.run();
	return 0;
}

D.Santa's Bot

题意:有n个孩子,每个孩子都有k个想要的礼物,每个礼物都有不同编号。现在有个算法,首先随机选一个孩子,之后从这个孩子的愿望清单里面随机选一个礼物,之后再随机选一个孩子,把刚刚那个礼物送给这个孩子。问有多少可能性,使得能送对。

思路:首先统计所有礼物被选中的概率,显然是读入的时候碰到一次就+\(\frac{1}{n}*\frac{1}{k}\)。之后由于最后一次也是随机选要送的人,所以把每种礼物的被选中的概率*想要它的孩子个数/n即可。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define mid ((l+r)>>1)
const int M=1e6+20,P=998244353;
int Inv[M];
void ln_Inv(int p){  
    Inv[0]=Inv[1]=1;
    for(int i=2;i<=1e6;i++)
        Inv[i]=1LL*(p-p/i)*Inv[p%i]%p; 
}  
struct Task{
	int n,giftnum[M],giftprob[M];
	void run(){
		scanf("%d",&n);
		for(int i=1;i<=n;++i){
			int k;
			scanf("%d",&k);
			int prob=1LL*Inv[n]*Inv[k]%P;
			for(int j=1;j<=k;++j){
				int c;
				scanf("%d",&c);
				++giftnum[c];
				giftprob[c]=(giftprob[c]+prob)%P;
			}
		}
		int ans=0;
		for(int i=1;i<=1e6;++i)
			ans=(ans+1LL*giftprob[i]*giftnum[i]%P*Inv[n]%P)%P;
		printf("%d\n",ans);
	}
}t;
int main(){
	ln_Inv(P);
	t.run();
	return 0;
}

posted on 2019-12-28 00:58  diorvh  阅读(183)  评论(0编辑  收藏  举报