Educational Codeforces Round 79 (Rated for Div. 2)(Aabc字符串排列,B枚举+二分,C线段树+栈,D概率dp)

拟墨画扇 提交于 2019-12-28 17:18:48

题目链接

A. New Year Garland

给你a,b,c,值代表a个A字符,b个B字符,c个C字符。。

问能否构造一个相邻两个字符都不相同的字符串,所有字符都必须用完。

做法:三个值从小到大排序,最大的值应该是这样分布的:A  A A B B B B 那么c的最大值就是a+b+1

c取值最小值是这样分布的:B A B A B A B  那么C必须是大于等于b-a-1

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=(b);++i)
    #define mem(a,x) memset(a,x,sizeof(a))
    #define pb push_back
    #define pi pair<int, int>
    #define mk make_pair
    using namespace std;
    typedef long long ll;
    ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
    int a[10];
    int main()
    {
        int n=3;
    	int _;cin>>_;while(_--)
    	{
    	    for(int i=1;i<=n;++i){
                scanf("%d",&a[i]);
    	    }
    	    sort(a+1,a+1+n);
    	    if(a[2]-a[1]-1<=a[3]&&a[3]<=a[1]+a[2]+1) puts("YES");
    	    else puts("NO");
    	}
    }

B. Verse For Santa

给你n个物品价值val[i],和s你有的硬币值。

现在你必须从1开始往后按顺序买,能买就买,买不了就停止了

现在你可选择跳过一个物品,使得后面能买的更多,输出你所跳过的那个物品的位置。没有跳过输出0

做法:s在前缀和里二分得到id值。从1到id里枚举去掉当前值,再继续二分,此时硬币值变成了 s+=a[i]。维护最大值即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10;
int a[N],n;
ll s;
ll sum[N];
int main()
{
    int n=3;
	int _;cin>>_;while(_--)
	{
        scanf("%d%lld",&n,&s);
        for(int i=1;i<=n;++i) {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
//        for(int i=1;i<=n;++i) printf("%lld ",sum[i]);
//        puts("");
        if(s>=sum[n]){
            printf("0\n");
            continue;
        }
        int mx=upper_bound(sum+1,sum+1+n,s)-sum;
        int id=mx;
        mx--;
 
        int ans=0;
        //printf("mx:%d\n",mx);
 
        for(int i=1;i<=id;++i){
            ll tmp=s+a[i];
            int t=upper_bound(sum+1,sum+1+n,tmp)-sum-1;
//            if(t>=i){
//                tmp+=a[i];
//                t=upper_bound(sum+1,sum+1+n,tmp)-sum-1;
//            }
 
            //printf("tmp:%lld t:%d\n",tmp,t);
            //printf("t:%d\n",t);
 
            if(t>mx){
                mx=t;
                ans=i;
            }
        }
        printf("%d\n",ans);
	}
}

C. Stack of Presents

题意:输入n,m,

n个礼物在一个栈内,1位置在栈顶

m个物品清单

现从1到m按顺序分配礼物,礼物li。然后在礼物栈内不断的出栈,直到了礼物st[i]==li[i],此时可以选择将所有出栈物品按照自己想要的顺序入栈,或者继续出栈。。。‘

做法:枚举礼物清单,若当前礼物没有出栈过,那么一直出栈出栈,并将出栈过的礼物标记一个代表出栈过,直到找到当前礼物,更新答案,这里我用线段树维护区间和查询在i点前面的数量,单点更新出栈的礼物。

继续枚举下一个礼物清单,若上一次出栈过,那么就按某种合法顺序入栈使得只需要出一次栈即可,

继续枚举下一个礼物清单,若上一次出栈过,同上做法ans+=1,若没有出栈过,因为之前已经全部入栈。。。重新枚举,并求前缀和。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10;
int vis[N],li[N],st[N],id[N],in[N];
int n,m;
int a[10];
int sum[4*N];
int qu(int id,int l,int r,int ql,int qr)
{
    if(qr<ql) return 0;
    if(ql<=l&&r<=qr){
        return sum[id];
    }
    int mid=l+r>>1;
    //printf("mid:%d\n",mid);
 
    int res=0;
    if(ql<=mid) res+=qu(id<<1,l,mid,ql,qr);
    if(qr>mid) res+=qu(id<<1|1,mid+1,r,ql,qr);
    return res;
}
void up(int id,int l,int r,int pos,int val)
{
    if(l==r){
        sum[id]+=val;
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) up(id<<1,l,mid,pos,val);
    else up(id<<1|1,mid+1,r,pos,val);
    sum[id]=sum[id<<1]+sum[id<<1|1];
}
void build(int id,int l,int r)
{
    if(l==r){
        sum[id]=1;
        return ;
    }
    int mid=l+r>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    sum[id]=sum[id<<1]+sum[id<<1|1];
}
int main()
{
    int n=3;
	int _;cin>>_;while(_--)
	{
	    scanf("%d%d",&n,&m);
 
	    for(int i=1;i<=n;++i){
            scanf("%d",&st[i]);
            id[st[i]]=i;
            vis[i]=in[i]=0;
	    }
	    for(int i=1;i<=m;++i){
            scanf("%d",&li[i]);
            in[li[i]]=1;
	    }
	    build(1,1,n);
	    //printf("****\n");
 
 
	    int l=0,pre;
	    ll ans=0;
	    int ty=0;
	    for(int i=1;i<=m;++i){
            if(vis[li[i]]==0){//之前未出现
                ty=0;
                pre=l+1;
                for(int j=l+1;j<=n;++j){
                    if(st[j]==li[i]){
                        ty=1;
                        int t=qu(1,1,n,1,j-1);
                        up(1,1,n,j,-1);
 
                        //printf("t:%d\n",t);
                        ans+=2ll*t+1;
                        l=j;
                        break;
                    }
                    vis[st[j]]=1;
                }
            }
            else{
                if(ty==1){
                    ans++;
                }
                else{
                    ty=1;
                    int t=qu(1,1,n,1,id[st[i]]-1);
 
                    ans+=2ll*t+1;
                }
                up(1,1,n,id[st[i]],-1);
            }
	    }
	    printf("%lld\n",ans);
	}
}#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10;
int vis[N],li[N],st[N],id[N],in[N];
int n,m;
int a[10];
int sum[4*N];
int qu(int id,int l,int r,int ql,int qr)
{
    if(qr<ql) return 0;
    if(ql<=l&&r<=qr){
        return sum[id];
    }
    int mid=l+r>>1;
    //printf("mid:%d\n",mid);
 
    int res=0;
    if(ql<=mid) res+=qu(id<<1,l,mid,ql,qr);
    if(qr>mid) res+=qu(id<<1|1,mid+1,r,ql,qr);
    return res;
}
void up(int id,int l,int r,int pos,int val)
{
    if(l==r){
        sum[id]+=val;
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) up(id<<1,l,mid,pos,val);
    else up(id<<1|1,mid+1,r,pos,val);
    sum[id]=sum[id<<1]+sum[id<<1|1];
}
void build(int id,int l,int r)
{
    if(l==r){
        sum[id]=1;
        return ;
    }
    int mid=l+r>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    sum[id]=sum[id<<1]+sum[id<<1|1];
}
int main()
{
    int n=3;
	int _;cin>>_;while(_--)
	{
	    scanf("%d%d",&n,&m);
 
	    for(int i=1;i<=n;++i){
            scanf("%d",&st[i]);
            id[st[i]]=i;
            vis[i]=in[i]=0;
	    }
	    for(int i=1;i<=m;++i){
            scanf("%d",&li[i]);
            in[li[i]]=1;
	    }
	    build(1,1,n);
	    //printf("****\n");
 
 
	    int l=0,pre;
	    ll ans=0;
	    int ty=0;
	    for(int i=1;i<=m;++i){
            if(vis[li[i]]==0){//之前未出现
                ty=0;
                pre=l+1;
                for(int j=l+1;j<=n;++j){
                    if(st[j]==li[i]){
                        ty=1;
                        int t=qu(1,1,n,1,j-1);
                        up(1,1,n,j,-1);
 
                        //printf("t:%d\n",t);
                        ans+=2ll*t+1;
                        l=j;
                        break;
                    }
                    vis[st[j]]=1;
                }
            }
            else{
                if(ty==1){
                    ans++;
                }
                else{
                    ty=1;
                    int t=qu(1,1,n,1,id[st[i]]-1);
 
                    ans+=2ll*t+1;
                }
                up(1,1,n,id[st[i]],-1);
            }
	    }
	    printf("%lld\n",ans);
	}
}

D. Santa's Bot

题意:等概率从n个小孩里选一个小孩x,从小孩x想要的礼物里等概率选一个礼物y,等概率分给n个小孩中的小孩z,如果z也正好想要这个礼物,就是valid,求valid方案数/总方案数

做法:枚举小孩和当前小孩礼物。当前礼物贡献的答案就是(1/n)*(1/k)*(拥有此礼物的小孩/n)全部相加即可。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=(b);++i)
    #define per(i,a,b) for(int i=a;i>=(b);--i)
    #define in(x) scanf("%d",&x)
    #define ind(x) scanf("%lld",&x)
    #define out(x) printf("%d ",x);
    #define outln(x) printf("%lld\n",x);
    #define bug(x) cout<<#x<<" is "<<x<<endl
    #define mem(a,x) memset(a,x,sizeof(a))
    #define pb push_back
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    #define PE(x,y) x=((x)+(y))%mod
    ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
     
    ll powmod(ll a,ll b) {ll res=1;a%=mod;
    for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
     
    const int N=1e6+10;
    vector<int>G[N];
    int n;
    int vis[N];
    int main()
    {
    	scanf("%d",&n);
    	ll fm=0;
    	for(int i=1;i<=n;++i){
            int k;
            scanf("%d",&k);
            fm+=k;
            for(int j=1;j<=k;++j){
                int x;
                scanf("%d",&x);
                G[i].push_back(x);
                vis[x]++;
            }
    	}
     
    	ll ans=0;
    	for(int i=1;i<=n;++i){
            ll num=0;
            ll k=G[i].size();
            for(int v:G[i]){
                ans=(ans+powmod(n,mod-2)*powmod(k,mod-2)%mod*1ll*vis[v]%mod*powmod(n,mod-2)%mod)%mod;
            }
    	}
    	printf("%lld\n",ans);
     
    	//printf("%lld\n",(powmod(8,mod-2)+powmod(4,mod-2)+powmod(2,mod-2))%mod);
     
    	//fz=7,fm=8;
    	//printf("fz:%lld fm:%lld\n",fz,fm);
    	//printf("%lld\n",fz*powmod(fm,mod-2)%mod);
    }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!