• 2018 Multi-University Training Contest 3


    Problem A. Ascending Rating

    题意:

      给出一个序列的前k项,后面的n-k+1项可由推出,定义一个区间的maxrating为区间的最大值,count为区间最大值的变换次数,给定子区间的长度m,求

    分析:

      首先求区间最大值,这是单调队列的经典问题就不用说了。对于变换次数,考虑维护单调递增序列或者维护单调递减序列,但是仔细一想好像都不对,因为我们在抛出之前区间的点时,会对之后的区间造成影响。如果反过来想一下,我们从后开始循环,维护一个单调递减序列,单调队列中元素个数就是变换次数,考虑区间变换时抛出超过区间范围的点,而右边的点对左边的点是没有影响的,所以我们就完美的解决了这个问题。做过很多这种要反着想的题,但是一比赛就不会,哇的一下就哭出来了.jpg。

    代码:

    #include <map>
    #include <queue>
    #include <math.h>
    #include <string>
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define cls(x) memset(x,0,sizeof(x))
    #define clslow(x) memset(x,-1,sizeof(x))
    
    const int maxn=7e7+100;
    
    int a[maxn];
    int que[maxn],maxval[maxn],cnt[maxn];
    
    void getMax(int n,int k)
    {
        int head=0,rear=0;
        for(int i=1;i<=n;i++){
            while(rear>head&&a[que[rear-1]]<=a[i])   rear--;
            que[rear++]=i;
            if(i<k) continue;
            while(que[head]<i-k+1)  head++;
            maxval[i]=a[que[head]];
        }
    }
    
    void getCnt(int n,int k)
    {
        int head=0,rear=0;
        for(int i=n;i>=1;i--){
            while(rear>head&&a[que[rear-1]]<=a[i])   rear--;
            que[rear++]=i;
            if(i>n-k+1) continue;
            while(que[head]>i+k-1)  head++;
    //        cout<<i+k-1<<" "<<head<<" "<<rear<<endl;
            cnt[i+k-1]=rear-head;
        }
    }
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        int T,n,m,k,p,q,r,mod;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d%d%d%d%d",&n,&m,&k,&p,&q,&r,&mod);
            for(int i=1;i<=k;i++){
                scanf("%d",&a[i]);
            }
            for(int i=k+1;i<=n;i++){
                a[i]=((ll)p%mod*a[i-1]%mod+(ll)q%mod*i%mod+r%mod)%mod;
            }
    
            getMax(n,m);
            getCnt(n,m);
    
            ll sum1=0,sum2=0;
            for(int i=m;i<=n;i++){
    //            cout<<i<<" "<<maxval[i]<<" "<<cnt[i]<<endl;
                sum1+=maxval[i]^(i-m+1);
                sum2+=cnt[i]^(i-m+1);
            }
            printf("%lld %lld
    ",sum1,sum2);
        }
        return 0;
    }
    View Code

    Problem C. Dynamic Graph Matching

    题意:

      定义一个图的匹配为没有公共顶点的边的集合。+ u v表示在u,v顶点之间连一条边,- u v表示去掉u,v顶点之间的一条边。问图的匹配数分别为1,2……n/2时(集合中边的数量),对应有多少种拿法?

    分析:

      我的理解是用二进制中的每一位代表一个顶点,为1则代表相应的顶点被选。

      dp【i】表示i的二进制中为1的位对应的顶点被选的情况下,一共有多少种方案数。

      当添加一条边时,所有同时包含u,v两个顶点的状态s需要更新,dp【s】+=dp【s-u-v】,同理当删除一条边时,dp【s】-=dp【s-u-v】。

      更新dp【i】时,相应的答案也需要进行更新,ans【bit【i】】+=(-=)dp【s-u-v】(bit【i】表示i的二进制中有几个1)。

      参考资料:大佬博客(以上为对大佬思路的理解)

    代码:

    #include <map>
    #include <queue>
    #include <math.h>
    #include <string>
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define cls(x) memset(x,0,sizeof(x))
    #define clslow(x) memset(x,-1,sizeof(x))
    
    const int mod=1e9+7;
    const int maxn=1<<11;
    
    char op;
    int n,m,T;
    
    int bit[maxn];
    ll dp[maxn],ans[11];
    
    //计算x的二进制中有多少1
    int calc(int x)
    {
        int cnt=0;
        while(x)
        {
            cnt++;
            x-=(x&-x);
        }
        return cnt;
    }
    
    void init()
    {
        for(int i=1;i<(1<<10);i++){
            bit[i]=calc(i);
        }
    }
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        init();
        scanf("%d",&T);
        while(T--)
        {
            cls(dp);
            cls(ans);
            dp[0]=1;
    
            scanf("%d%d",&n,&m);
            while(m--){
                int u,v,sign;
                scanf("
    %c %d%d",&op,&u,&v);
    
                //第1个点的状态用二进制表示为00000000001
                //第2个点的状态用二进制表示为00000000010
                //……
                //所以在这里手动减1
                u--,v--;
                if(op=='+') sign=1;
                else        sign=-1;
                for(int i=1;i<(1<<n);i++){
                    //i&(1<<u)如果不为0,则代表在第u位都为1,即i包括u顶点
                    if((i&(1<<u))&&(i&(1<<v))){
                        //如果添加一条边,加上增加的方案数,否则减
                        dp[i]+=sign*dp[i-(1<<u)-(1<<v)];
                        //考虑更新时对答案的贡献
                        ans[bit[i]]+=sign*dp[i-(1<<u)-(1<<v)];
                        dp[i]=(dp[i]%mod+mod)%mod;
                        ans[bit[i]]=(ans[bit[i]]%mod+mod)%mod;
                    }
                }
    
                for(int i=2;i<=n;i+=2){
                    printf("%lld%c",ans[i],(i==n?'
    ':' '));
                }
            }
        }
        return 0;
    }
    View Code

    Problem D. Euler Function

    题意:

      找到第k小的正数,对于euler(n)的值为合数的集合。

    分析:

      看了大佬们3分钟就ac了,我就懂了,打表之后发现只有当n=1,2,3,4,6时,euler(n)不是合数。

    代码:

    #include <map>
    #include <math.h>
    #include <string>
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define cls(x) memset(x,0,sizeof(x))
    #define clslow(x) memset(x,-1,sizeof(x))
    
    const int maxn=1e5;
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        int k,T,ans;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&k);
            if(k==1)  ans=5;
            else      ans=k+5;
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    Problem F. Grab The Tree

    题意:

      给出一颗树,Q能够拿图中任意数量点,但是需要保证拿的点中任意两点没有边相连,T拿Q拿后剩下的点,定义每个人的分数为所拿的点的异或值,分数大的赢。

    分析:

      当时想的是如果所有点的异或值不为0,那么肯定二进制中为1的位对应的顶点有奇数个,考虑只拿一个最高位对应的顶点,则Q的分数一定比T高。否则,如果异或值

    为0,则Q的所有点^T的所有点=0,即Q的异或值等于T的异或值。

    代码:

    #include <map>
    #include <queue>
    #include <math.h>
    #include <string>
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define cls(x) memset(x,0,sizeof(x))
    #define clslow(x) memset(x,-1,sizeof(x))
    
    const int mod=1e9+7;
    const int maxn=1<<11;
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        int n,T;
        scanf("%d",&T);
        while(T--)
        {
            int XOR;
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                int p;
                scanf("%d",&p);
                if(i==1)    XOR=p;
                else        XOR^=p;
            }
            for(int i=1;i<n;i++){
                int u,v;
                scanf("%d%d",&u,&v);
            }
            if(XOR) printf("Q
    ");
            else    printf("D
    ");
        }
        return 0;
    }
    View Code

    Problem L. Visual Cube

    题意:

      画立方体。

    分析:

      模拟就好了。

    代码:

    #include <map>
    #include <math.h>
    #include <string>
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define cls(x) memset(x,0,sizeof(x))
    #define clslow(x) memset(x,-1,sizeof(x))
    
    const int maxn=1e3;
    
    char rect[maxn][maxn];
    
    void print(int n,int m)
    {
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                printf("%c",rect[i][j]);
            }
            printf("
    ");
        }
    }
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        int l,w,h,T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d",&l,&w,&h);
            int rest=2*w;
            int n=rest+h*2+1,m=rest+l*2+1;
    
            //左上
            for(int i=1;i<=rest;i++){
                for(int j=1;j<=rest-i+1;j++){
                    rect[i][j]='.';
                }
            }
            //上面
            int cnt=0;
            for(int i=1;i<=rest;i++){
                char lch,rch;
                if(i&1) lch='+',rch='-';
                else    lch='/',rch='.';
                bool flag=true;
                for(int j=rest-i+2;j<=m-cnt;j++){
                    if(flag)    rect[i][j]=lch;
                    else        rect[i][j]=rch;
                    flag=!flag;
                }
                cnt++;
            }
            //正面
            for(int i=rest+1;i<=n;i++){
                char lch,rch;
                if(i&1) lch='+',rch='-';
                else    lch='|',rch='.';
                bool flag=true;
                for(int j=1;j<=2*l+1;j++){
                    if(flag)    rect[i][j]=lch;
                    else        rect[i][j]=rch;
                    flag=!flag;
                }
                cnt++;
            }
            //右面
            cnt=0;
            for(int i=1;i<=n;i++){
                int last;
                char pre,now;
                if(i<=rest) last=m-cnt;
                else        last=2*l+1;
                pre=rect[i][last];
                for(int j=last+1;j<=m;j++){
                    if(pre=='/')    now='|';
                    else if(pre=='|')   now='/';
                    else if(pre=='+')   now='.';
                    else if(pre=='.')   now='+';
                    rect[i][j]=now;
                    pre=now;
                }
                cnt++;
            }
            //右下
            cnt=0;
            for(int i=n-rest+1;i<=n;i++){
                for(int j=m-cnt;j<=m;j++){
                    rect[i][j]='.';
                }
                cnt++;
            }
    
            print(n,m);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    pip错误:'utf-8' codec can't decode byte解决方法
    windows中python2与python3共存
    Alpha 冲刺 (3/10)
    Alpha 冲刺 (2/10)
    Alpha 冲刺 (1/10)
    项目需求分析报告答辩总结
    项目选题报告答辩总结
    项目UML设计(团队)
    # 第七次作业--项目需求分析(团队)
    结对项目--第二次作业
  • 原文地址:https://www.cnblogs.com/shutdown113/p/9396057.html
Copyright © 2020-2023  润新知