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
原文地址:https://www.cnblogs.com/shutdown113/p/9396057.html