zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校赛(第四场)

    A题  https://ac.nowcoder.com/acm/contest/884/A

    题意:给定n个点和n-1条边构成一颗树,k个人,最后一行给出k个人的位置来,问所有人到达树的一点会面所用的最短时间是什么,所需最短时间是每个人到达那个地方的最长时间。

    题解:类似求树的直径,从所给的人的位置为起点,然后求到另一个给的人的位置的最大值,找到最大值的这个位置再搜一遍最大值,这个距离再除2向上取整就是答案了。

    官方题解:

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int ll;
    typedef unsigned long long int ull;
    const int inf = 0x3f3f3f3f;
    int dir[8][2]={{1,0},{0,1},{1,1},{1,-1},{-1,1},{-1,-1},{0,-1},{-1,0}};
    #define pi acos(-1)
    #define ls rt<<1
    #define rs rt<<1|1
    #define me0(s) memset(s,0,sizeof(s))
    #define me1(s) memset(s,1,sizeof(s))
    #define mef(s) memset(s,-1,sizeof(s))
    #define meinf(s) memset(s,inf,sizeof(s))
    const int N=200005;
    inline int read() {
        char c=getchar(); int x=0, f=1;
        while(c<'0'|c>'9') {if(c=='-') f=-1;c=getchar();}
        while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
        return x*f;
    }
    ll q_pow(ll a,ll b,ll mod){
        ll anss=1;
        while(b){
            if(b&1) anss=anss*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return anss;
    }
    ll q_mul(ll a,ll b,ll mod){
        ll anss=0;
        while(b){
            if(b&1) anss=(anss+a)%mod;
            a=(a+a)%mod;
            b>>=1;
        }
        return anss;
    }
    struct node{
        int v,next;
    }edge[N];
    int cnt,fir[N],vis1[N],a[N];
    void init(){
        cnt=0;
        mef(fir);
    }
    void add(int u,int v){
        edge[cnt].v=v;
        edge[cnt].next=fir[u];
        fir[u]=cnt++;
    }
    int bfs(int x,int y){
        int vis[N],ans1=x,ans2=0;
        me0(vis);
        queue<pair<int,int> > q;
        q.push(make_pair(x,0));
        vis[x]=1;
        while(!q.empty()){
            int lx=q.front().first,ly=q.front().second;
            if(vis1[lx]){
                ans1=lx;
                ans2=ly;
            }
            q.pop();
            for(int i=fir[lx];i!=-1;i=edge[i].next){
                int lv=edge[i].v;
                if(!vis[lv]){
                    q.push(make_pair(lv,ly+1));
                    vis[lv]=1;
                }
            }
        }
        if(!y) return ans1;
        else return ans2;
    }
    int main(int argc, char * argv[]){
        ios::sync_with_stdio(false);
        int n,k;
        cin>>n>>k;
        init();
    
        for(int i=1;i<=n-1;i++){
            int a,b;
            cin>>a>>b;
            add(a,b);
            add(b,a);
        }
        me0(vis1);
        for(int i=1;i<=k;i++){
            cin>>a[i];
            vis1[a[i]]=1;
        }
        int re=bfs(a[1],0);
        re=bfs(re,1);
        cout<<re/2+re%2<<endl;
        return 0;
    }

    B题 https://ac.nowcoder.com/acm/contest/884/B

     好像说是线段树加线性基的交,还不会,先码着,学了来补

    C题 https://ac.nowcoder.com/acm/contest/884/C   

    题意:给定两个长度为n的数组a和b,求a数组任意一区间的最小值乘b数组相同区间和的最大值是多少。其中a,b包含负数(重点)。

    题解:和南昌网络邀请赛题目一样,只不过是用前缀和存b数组就是了。

    一开始时限1s会卡线段树,后面抬一手时限放了3s线段树也能过了。

    官方题解:

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    int dir[8][2]={{1,0},{0,1},{1,1},{1,-1},{-1,1},{-1,-1},{0,-1},{-1,0}};
    #define pi acos(-1)
    #define ls rt<<1
    #define rs rt<<1|1
    #define inf 1e18
    #define me0(s) memset(s,0,sizeof(s))
    #define me1(s) memset(s,1,sizeof(s))
    #define mef(s) memset(s,-1,sizeof(s))
    #define meinf(s) memset(s,inf,sizeof(s))
    const int N=3e6+5;
    ll a[N],b[N],sum[N],Min[N<<2],Max[N<<2];
    stack <ll> s;
    void pushup(int rt){
        Max[rt]=max(Max[ls],Max[rs]);
        Min[rt]=min(Min[ls],Min[rs]);
    }
    void build(int l,int r,int rt){
        if(l==r){
            Max[rt]=Min[rt]=sum[l];
            return ;
        }
        int m=(l+r)>>1;
        build(l,m,ls);
        build(m+1,r,rs);
        pushup(rt);
    }
    ll query_max(int L,int R,int l,int r,int rt){
        if(l<=L&&r>=R){
            return Max[rt];
        }
        ll ans=-inf;
        int m=(L+R)>>1;
        if(l<=m) ans=max(ans,query_max(L,m,l,r,ls));
        if(r>m) ans=max(ans,query_max(m+1,R,l,r,rs));
        return ans;
    }
    ll query_min(int L,int R,int l,int r,int rt){
        if(l<=L&&r>=R){
            return Min[rt];
        }
        ll ans=inf;
        int m=(L+R)>>1;
        if(l<=m) ans=min(ans,query_min(L,m,l,r,ls));
        if(r>m) ans=min(ans,query_min(m+1,R,l,r,rs));
        return ans; 
    }
    int n;
    int l[N],r[N];
    int main(int argc, char * argv[]) 
    {
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        for(int i=1;i<=n;i++){
            cin>>b[i];
            sum[i]=sum[i-1]+b[i];
        }
        build(1,n,1); //线段树存的是区间和的值
        for(int i=1;i<=n;i++){
            while(s.size()&&a[s.top()]>=a[i]) s.pop();
            if(s.size()) l[i]=s.top()+1;
            else l[i]=1;
            s.push(i);
        }
        while(s.size()) s.pop();
        for(int i=n;i>=1;i--){
            while(s.size()&&a[s.top()]>=a[i]) s.pop();
            if(s.size()) r[i]=s.top()-1;
            else r[i]=n;
            s.push(i);
        } //左右第一个比他大的地方
        ll ans=-inf;
        for(int i=1;i<=n;i++){
            if(a[i]>=0) ans=max(ans,(sum[r[i]]-sum[l[i]-1])*a[i]);
            else{
                ll maxn=query_max(1,n,max(l[i]-1,1),max(i-1,1),1);
                if(l[i]==1&&maxn<0) maxn=0;
                ll minn=query_min(1,n,i,r[i],1);
                ans=max(ans,(minn-maxn)*a[i]);
            } 
        }
        cout<<ans<<endl;
        return 0;
    }

    D题 https://ac.nowcoder.com/acm/contest/884/D

    题意:给定一个数a,要求构造最少个数的3的倍数使得这些数的按位或的和为a。

    官方题解:

     代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    int dir[8][2]={{1,0},{0,1},{1,1},{1,-1},{-1,1},{-1,-1},{0,-1},{-1,0}};
    #define pi acos(-1)
    #define ls rt<<1
    #define rs rt<<1|1
    #define me0(s) memset(s,0,sizeof(s))
    #define me1(s) memset(s,1,sizeof(s))
    #define mef(s) memset(s,-1,sizeof(s))
    #define meinf(s) memset(s,inf,sizeof(s))
    #define inf 1e18
    const int N=105;
    ll f1[N],f2[N];
    int a[N];
    int main(int argc, char * argv[]) 
    {
        ios::sync_with_stdio(false);
        int t;
        cin>>t;
        while(t--){
            ll n;
            cin>>n;
            if(n%3==0) cout<<1<<" "<<n<<endl;
            int len=0;
            ll m=n;
            while(m){
                a[++len]=m%2;
                m/=2;
            }
            ll x=1;
            int ans1=0;
            int ans2=0;
            for(int i=1;i<=len;i++){
                if(a[i]){
                    if(x%3==1){
                        f1[++ans1]=x;
                    }
                    else if(x%3==2){
                        f2[++ans2]=x;
                    }
                }
                x=x*2;
            }
            if(n%3==1){
                if(ans1>=2){
                    cout<<2<<" ";
                    cout<<n-f1[1]<<" "<<n-f1[2]<<endl;
                }
                else if(ans1==1){
                    cout<<2<<" ";
                    cout<<n-f1[1]<<" "<<f1[1]+f2[1]<<endl;
                }
                else if(ans2>=3){
                    cout<<2<<" ";
                    cout<<f2[1]+f2[2]+f2[3]<<" "<<n-f2[1]-f2[2]<<endl;
                }
            }
             else if(n%3==2){
                 if(ans2>=2){
                    cout<<2<<" ";
                    cout<<n-f2[1]<<" "<<n-f2[2]<<endl;
                }
                else if(ans2==1){
                    cout<<2<<" ";
                    cout<<n-f2[1]<<" "<<f2[1]+f1[1]<<endl;
                }
                else if(ans1>=3){
                    cout<<2<<" ";
                    cout<<f1[1]+f1[2]+f1[3]<<" "<<n-f1[1]-f1[2]<<endl;
                }
             }
        }
        return 0;
    }

    J题 https://ac.nowcoder.com/acm/contest/884/J

    题意:n个点m条边,从点s到t的路径中,选择最短路,其中你可以将任意k条边的花费变为0,问最小花费是多少

    题解:最短路,队友拍的,不懂。

    官方题解:

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<cmath>
    using namespace std;
    #define LL long long
    const int MOD=1e9+7;
    const int inf=0x3f3f3f3f;
    const LL inff=0x3f3f3f3f3f3f3f3f;
    const LL MAX_N=10005;
    const LL MAX_M=100005;
    #define MEF(x) memset(x,-1,sizeof(x))
    #define ME0(x) memset(x,0,sizeof(x))
    #define MEI(x) memset(x,inf,sizeof(x))
    struct Node
    {
        LL i,k,dis;
     
        bool operator <(const Node &a)const
        {
            return dis>a.dis;
     
        }
    };
    struct Edge
    {
        LL v,w,next;
    }edge[MAX_M];
    LL dis[MAX_N][15];
     
    LL first[MAX_N],cnt,vis[MAX_N][15];
    void add(LL u,LL v,LL w)
    {
        edge[cnt].v=v;
        edge[cnt].w=w;
        edge[cnt].next=first[u];
        first[u]=cnt++;
    }
    void dijstra(LL s,LL t,LL k)
    {
        priority_queue<Node> pq;
        MEI(dis);
        ME0(vis);
        Node l;
        l.i=s;
        l.k=0;
        l.dis=0;
     
        dis[s][0]=0;
     
        pq.push(l);
        while(!pq.empty())
        {
            l=pq.top();
            pq.pop();
            LL li=l.i,lk=l.k;
            if(vis[li][lk])
            {
                continue;
            }
            vis[li][lk]=1;
            for(LL i=first[li];i!=-1;i=edge[i].next)
            {
                LL lv=edge[i].v;
                if(!vis[lv][lk]&&dis[lv][lk]>dis[li][lk]+edge[i].w)
     
                {
                    dis[lv][lk]=dis[li][lk]+edge[i].w;
     
                    l.i=lv;
                    l.k=lk;
                    l.dis=dis[lv][lk];
     
                    pq.push(l);
                }
                if(lk+1<=k&&!vis[lv][lk+1]&&dis[lv][lk+1]>dis[li][lk])
     
                {
                    dis[lv][lk+1]=dis[li][lk];
     
                    l.i=lv;
                    l.k=lk+1;
                    l.dis=dis[lv][lk+1];
     
                    pq.push(l);
                }
            }
        }
        LL ans=dis[t][k];
        for(int i=0;i<=k;i++)
        {
            ans=min(dis[t][i],ans);
        }
        printf("%lld
    ",ans);
    }
    int main()
    {
        LL n,m,k,st,ed,a,b,c;
        scanf("%lld%lld%lld%lld%lld",&n,&m,&st,&ed,&k);
        cnt=0;
        MEF(first);
        for(LL m1=1;m1<=m;m1++)
        {
            scanf("%lld%lld%lld",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        dijstra(st,ed,k);
        return 0;
    }

    K题: https://ac.nowcoder.com/acm/contest/884/K

    题意:给定一串字符,求字符子串能构成300倍数出现的次数,0,00,000以及前导零都算。

    题解:比赛时候刷刷刷的过人,我们辛辛苦苦暴力还超时,自闭。(万物皆可dp)

    官方题解:

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    int dir[8][2]={{1,0},{0,1},{1,1},{1,-1},{-1,1},{-1,-1},{0,-1},{-1,0}};
    #define pi acos(-1)
    #define ls rt<<1
    #define rs rt<<1|1
    #define me0(s) memset(s,0,sizeof(s))
    #define me1(s) memset(s,1,sizeof(s))
    #define mef(s) memset(s,-1,sizeof(s))
    #define meinf(s) memset(s,inf,sizeof(s))
    #define inf 1e18
    const int N=1e6+6;
    inline int read() {
        char c=getchar(); int x=0, f=1;
        while(c<'0'|c>'9') {if(c=='-') f=-1;c=getchar();}
        while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
        return x*f;
    }
    ll exgcd(ll a,ll b){
        if(b==0) return a;
        exgcd(b,a%b);
    }
    ll q_pow(ll a,ll b,ll mod){
        ll anss=1;
        while(b){
            if(b&1) anss=anss*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return anss;
    }
    ll q_mul(ll a,ll b,ll mod){
        ll anss=0;
        while(b){
            if(b&1) anss=(anss+a)%mod;
            a=(a+a)%mod;
            b>>=1;
        }
        return anss;
    }
    int a[N];
    int main(int argc, char * argv[]) 
    {
        ios::sync_with_stdio(false);
        string s;
        cin>>s;
        int sum=0;
        ll ans=0;
        a[0]++;
        for(int i=0;i<s.length();i++){
            sum+=s[i]-'0';
            sum%=3;
            if(s[i+1]=='0'&&s[i+2]=='0') ans+=a[sum];
            a[sum]++;
        }
        for(int i=0;i<s.length();i++){
            if(s[i]=='0') ans++;
            if(s[i]=='0'&&s[i+1]=='0') ans++;
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    Dynamics 365/CRM 实体设计技巧
    Dynamics 365/CRM 保存之后触发onchange
    编写C#程序,计算去除最大值和最小值之后的平均值
    Dynamics 365 WebResourceUtility 工具更新
    No sandboxworker process or sandbox hosts are currently avaliable
    C#
    Dynamics CRM 365 and Azure Service Bus – Queue
    双for循环
    java switch 的练习
    java__if_else 的练习
  • 原文地址:https://www.cnblogs.com/wushengyang/p/11262392.html
Copyright © 2011-2022 走看看