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

猜你喜欢

转载自www.cnblogs.com/diorvh/p/12110224.html
79