【日记】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;
}