zoukankan      html  css  js  c++  java
  • 10.5 考试 (感觉比较难)

    T1

    正解是 建26颗线段树,但是他们有人被卡常了...

    还是分块大法好,跑的最快

    直接记录下每一个块 26个字母出现次数,再打上升序还是降序的标记

    毕竟考试调了两个小时呢23333

     

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #define dd double
    #define mem(a,b) memset(a,b,sizeof(a))
    #define ll long long
    using namespace std;
    inline char readchar()
    {
        char q=getchar();
        while(q<'a'||q>'z')q=getchar();
        return q;
    }
    inline int read()
    {
        char q=getchar();int ans=0;
        while(q<'0'||q>'9')q=getchar();
        while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
        return ans;
    }
    const int N=100006;
    
    int n,m,fen;
    int s[N];
    
    int dui[N],L[1006],R[1006],len[1006];
    int num[1006][36],flag[1006];
    
    int t[36];
    
    inline void pushdown(int x)
    {
        if(flag[x]==-1)
            return ;
        int now;
        if(flag[x]==1)
        {
            now=L[x];
            for(int i=0;i<26;++i)
                while(num[x][i])
                    s[now++]=i,--num[x][i];
        }
        else
        {
            now=R[x];
            for(int i=0;i<26;++i)
                while(num[x][i])
                    s[now--]=i,--num[x][i];
        }
        flag[x]=-1;
    }
    
    inline void pushup(int x)
    {
        mem(num[x],0);
        for(int i=L[x];i<=R[x];++i)
            ++num[x][s[i]];
    }
    
    inline void get_sum(int l,int r)
    {
        int q1=min(r,R[dui[l]]);
        pushdown(dui[l]);
        for(int i=l;i<=q1;++i)
            ++t[s[i]];
        if(dui[l]!=dui[r])
        {
            pushdown(dui[r]);
            for(int i=L[dui[r]];i<=r;++i)
                ++t[s[i]];
        }
        for(int i=dui[l]+1;i<dui[r];++i)
            for(int j=0;j<26;++j)
                t[j]+=num[i][j];
    }
    
    inline void changesh(int l,int r)
    {
        get_sum(l,r);
        int q1=min(r,R[dui[l]]),now1,now2,temp;
        now1=0;
        now2=l;
        while(now2<=q1)
        {
            while(!t[now1])
                ++now1;
            s[now2]=now1;
            ++now2;
            --t[now1];
        }
        pushup(dui[l]);
        for(int i=dui[l]+1;i<dui[r];++i)
        {
            flag[i]=1;
            mem(num[i],0);
            now2=0;
            while(now2<len[i])
            {
                while(!t[now1])
                    ++now1;
                temp=min(len[i]-now2,t[now1]);
                num[i][now1]+=temp;
                now2+=temp;
                t[now1]-=temp;
            }
        }
        if(dui[l]!=dui[r])
        {
            now2=L[dui[r]];
            while(now2<=r)
            {
                while(!t[now1])
                    ++now1;
                s[now2]=now1;
                ++now2;
                --t[now1];
            }
            pushup(dui[r]);
        }
    }
    
    inline void changexi(int l,int r)
    {
        get_sum(l,r);
        int q1=max(l,L[dui[r]]),now1,now2,temp;
        now1=0;
    
        now2=r;
        while(now2>=q1)
        {
            while(!t[now1])
                ++now1;
            s[now2]=now1;
            --now2;
            --t[now1];
        }
        pushup(dui[r]);
        for(int i=dui[r]-1;i>dui[l];--i)
        {
            flag[i]=0;
            for(int j=0;j<26;++j)num[i][j]=0;
            now2=0;
            while(now2<len[i])
            {
                while(!t[now1])
                    ++now1;
                temp=(len[i]-now2<t[now1]?len[i]-now2:t[now1]);
                num[i][now1]+=temp;
                now2+=temp;
                t[now1]-=temp;
            }
        }
        if(dui[l]!=dui[r])
        {
            now2=R[dui[l]];
            while(now2>=l)
            {
                while(!t[now1])
                    ++now1;
                s[now2]=now1;
                --now2;
                --t[now1];
            }
            pushup(dui[l]);
        }
    }
    
    inline void out11()
    {
        for(int i=1;i<=dui[n];++i)
            pushdown(i);
        for(int i=1;i<=n;++i)
            printf("%c",s[i]+'a');
    }
    
    int main(){
    
        //freopen("T1.in","r",stdin);
        //freopen("T1.out","w",stdout);
    
        mem(flag,-1);
    
        n=read();m=read();
        //fen=(int)ceil(sqrt((dd)n*13.5+0.5));
        fen=(int)ceil(sqrt(n+0.5));
        for(int i=1;i<=n;++i)
        {
            s[i]=readchar()-'a';
            dui[i]=(i-1)/fen+1;
            ++num[dui[i]][s[i]];
        }
        for(int i=1;i<=dui[n];++i)
        {
            L[i]=(i-1)*fen+1;
            R[i]=min(n,i*fen);
            len[i]=R[i]-L[i]+1;
        }
        int op,l0,r0,now;
        for(int i=1;i<=m;++i)
        {
            l0=read();r0=read();op=read();
            if(l0>r0)
                swap(l0,r0);
            if(op==1)
                changesh(l0,r0);
            else
                changexi(l0,r0);
        }
        out11();
    }]
    T1

     

    T2

    考试执着的认为是 容斥,也想过dp,但是觉得就是...(容斥个??)

    f[i][j] 前i列中选了j列右区间的方案数

    考虑 第i列选右区间还是不选 再考虑左区间选的方案数,用排列计算

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cstdlib>
    #include <algorithm>
    #define ll long long
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    const int N=3006;
    const int mod=998244353;
    
    ll jie[N],jieni[N],ni[N];
    
    void chu()
    {
        ni[1]=1;
        for(int i=2;i<N;++i)
            ni[i]=(ll)(mod-mod/i)*ni[mod%i]%mod;
        jie[0]=jieni[0]=1;
        for(int i=1;i<N;++i)
        {
            jie[i]=jie[i-1]*i%mod;
            jieni[i]=jieni[i-1]*ni[i]%mod;
        }
    }
    
    inline ll A(int n,int m)
    {
        if(n<m)
            return 0;
        return jie[n]*jieni[n-m]%mod;
    }
    
    int n,m;
    int l[N],r[N];
    ll f[N][N];
    
    int jil[N],prel[N],jir[N],prer[N];
    
    void dp()
    {
        f[0][0]=1;
        for(int i=1;i<=m;++i)
            for(int j=0;j<=n;++j)
            {
                f[i][j]=(f[i][j]+f[i-1][j])%mod;
                if(j>0&&prer[i]-(j-1)>=0)
                //if(j>0)
                {
                    //printf("i=%d j=%d
    ",i,j);
                    f[i][j]=(f[i][j]+f[i-1][j-1]*(prer[i]-(j-1))%mod )%mod;
                }
                if(jil[i])
                {
                    if(j+prel[i]>i)
                        f[i][j]=0;
                    else
                        f[i][j]=f[i][j]*A(i-j-prel[i-1],jil[i])%mod;
                }
            }
    }
    
    int main(){
        
        //freopen("in.in","r",stdin);
    
        chu();
    
        scanf("%d%d",&n,&m);
        //printf("n=%d
    ",n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d%d",&l[i],&r[i]);
            ++jil[l[i]];
            ++jir[r[i]];
        }
        for(int j=1;j<=m;++j)
        {
            prel[j]=prel[j-1]+jil[j];
            prer[j]=prer[j-1]+jir[j];
        }
        dp();
        /*printf("
    ");
        for(int i=1;i<=m;++i)
        {
            for(int j=1;j<=n;++j)
                printf("%lld ",f[i][j]);
            printf("
    ");
        }*/
        cout<<f[m][n];
    }
    T2

     

    T3

    对手的变换其实是把 x循环左移一位...

    而x异或一部分数后再左移,相当于x先左移,前i个数异或和再左移

    之后就是:

    给m+1个数,选一个x,使得x与m+1个数异或和最小值最大

    这个可以把m+1个数建一颗0/1trie

    然后在树上走

    如果这个节点0/1儿子都有,你肯定得选1/0是最后这一位异或是0 (你要保证最小值)

    如果只有一个儿子,这一位你要选一个数 使其最后异或是1 (最大值)

    之后在得到的m+1个数里 找到ans

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cstdlib>
    #include <algorithm>
    #define ll long long
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    const int M=100006;
    struct son
    {
        son* ch[2];
        son()
        {
            ch[0]=ch[1]=NULL;
        }
    }*root;
    
    int n,m,maxp;
    int a[M],pre[M];
    
    int con;
    int b[M];
    
    void add(int x)
    {
        int temp;
        son *now=root;
        for(int i=n-1;i>=0;--i)
        {
            temp=0;
            if( (1<<i)&x )
                temp=1;
            if(now->ch[temp]==NULL)
                now->ch[temp]=new son();
            now=now->ch[temp];
        }
    }
    
    inline int move(int x)
    {
        return ((1<<(n-1))&x)?(((x<<1)&maxp)|1):((x<<1)&maxp);
    }
    
    inline int move2(int x)
    {
        return (1&x)?((x>>1)|(1<<(n-1))):(x>>1);
    }
    
    void dfs(son *x,int h,int now)
    {
        //printf("h=%d now=%d
    ",h,now);
        if(h==-1)
        {
            b[++con]=now;
            return ;
        }
        if(x->ch[0]!=NULL&&x->ch[1]!=NULL)
        {
            dfs(x->ch[0],h-1,now);
            dfs(x->ch[1],h-1,now);
        }
        else
            if(x->ch[0]!=NULL)
                dfs(x->ch[0],h-1,now|(1<<h));
        else
            if(x->ch[1]!=NULL)
                dfs(x->ch[1],h-1,now|(1<<h));
        return ;
    }
    
    void out11()
    {
        printf("%d %d %d
    ",move(1),move(2),move(3));
        printf("
    ");
        for(int i=1;i<=m;++i)
            printf("%d ",pre[i]);
        printf("
    ");
        for(int i=1;i<=con;++i)
            printf("%d ",b[i]);
        printf("
    ");
    }
    
    int main(){
    
        //freopen("in.in","r",stdin);
        //freopen("big2.in","r",stdin);
    
        scanf("%d%d",&n,&m);
        maxp=(1<<n)-1;
        for(int i=1;i<=m;++i)
        {
            scanf("%d",&a[i]);
            pre[i]=pre[i-1]^a[i];
        }
        b[++con]=pre[m];
        for(int i=1;i<=m;++i)
            b[++con]=move(pre[i])^(pre[m]^pre[i]);
    
        root=new son();
        for(int i=1;i<=con;++i)
            add(b[i]);
        con=0;
        dfs(root,n-1,0);
        int mx=-1,num=0;
        for(int i=1;i<=con;++i)
        {
            if(mx<b[i])
            {
                mx=b[i];
                num=1;
            }
            else
                if(mx==b[i])
                    ++num;
        }
        //out11();
        printf("%d
    %d",mx,num);
    }
    T3

     

    这次考试个人觉得比较难

    第一题调的时间太长,代码能力有待提升....

     

  • 相关阅读:
    c++的stack容器
    c++的deque容器
    Vector容器
    stl的string
    MATLAB 矩阵操作(三)
    MATLAB 矩阵操作(二)
    智慧树刷课
    MATLAB 将 n 美分转换成 25、10、5 和 1 美分的硬币总共有多少种转换方法?编写一个函数,传入参数 n,输出转换的种类
    MATLAB 图像处理于数字化之简单图像加密算法
    Python 第三方库的安装
  • 原文地址:https://www.cnblogs.com/A-LEAF/p/7631274.html
Copyright © 2011-2022 走看看