zoukankan      html  css  js  c++  java
  • [NOIP模拟测试11] 题解

    A.string

    和河北的一道省选题很像。考场上写的暴力桶排,正解其实就是优化一下这个思路。

    开线段树维护字符串中每个字母出现的次数。对于每条询问,区间查询、区间赋值维护即可。

    另外,本题卡常严重,正解能被卡到40到90不等。所以直接循环展开乱搞一波?

    暴力40分代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    const int N=100005;
    int a[N],bu[205],n,m;
    char str[N];
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void busort(int op,int l,int r)
    {
        for(int i=l;i<=r;i++)
            bu[a[i]]++;
        int tot=0;
        if(op)
        {
            for(int i=97;i<=122;i++)
                while(bu[i])a[l+(tot++)]=i,bu[i]--;
        }
        else
        {
            for(int i=122;i>=97;i--)
                while(bu[i])a[l+(tot++)]=i,bu[i]--;
        }
    }
    int main()
    {
        n=read();m=read();
        scanf("%s",str+1);
        for(int i=1;i<=n;i++)
            a[i]=(int)str[i];
        while(m--)
        {
            int l=read(),r=read(),op=read();
            busort(op,l,r);
        }
        for(int i=1;i<=n;i++)
        {
            char ch=(char)a[i];
            printf("%c",ch);
        }
        return 0;
    }

    被卡的90分代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    const int N=100005;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    int n,m,len;
    char str[N],ans[N];
    #define ls(k) k<<1
    #define rs(k) k<<1|1
    int num[N<<2][28],lz[N<<2],le[N<<2],re[N<<2];
    int res[28];
    void up(int k)
    {
        for(int i=1;i<=26;i++)
            num[k][i]=num[ls(k)][i]+num[rs(k)][i];
    }
    void build(int k,int l,int r)
    {
        lz[k]=0;le[k]=l,re[k]=r;
        if(l==r)
        {
            num[k][str[l]-'a'+1]=1;
            return ;
        }
        int mid=l+r>>1;
        build(ls(k),l,mid);
        build(rs(k),mid+1,r);
        up(k);
    }
    void down(int k)
    {
        memset(num[ls(k)],0,sizeof(num[ls(k)]));
        memset(num[rs(k)],0,sizeof(num[rs(k)]));
        num[ls(k)][lz[k]]=re[ls(k)]-le[ls(k)]+1;
        num[rs(k)][lz[k]]=re[rs(k)]-le[rs(k)]+1;
        lz[ls(k)]=lz[rs(k)]=lz[k];
        lz[k]=0;
    }
    void query(int k,int L,int R)
    {
        if(le[k]>=L&&R>=re[k])
        {
            for(int i=1;i<=26;i++)
                res[i]+=num[k][i];
            return ;
        }
        int mid=le[k]+re[k]>>1;
        if(lz[k])down(k);
        if(L<=mid)query(ls(k),L,R);
        if(R>mid)query(rs(k),L,R);
    }
    void change(int k,int L,int R,int val)
    {
        if(le[k]>=L&&R>=re[k])
        {
            memset(num[k],0,sizeof(num[k]));
            num[k][val]=re[k]-le[k]+1;
            lz[k]=val;
            return ;
        }
        int mid=le[k]+re[k]>>1;
        if(lz[k])down(k);
        if(L<=mid)change(ls(k),L,R,val);
        if(R>mid)change(rs(k),L,R,val);
        up(k);
    }
    void cacl(int k)
    {
        if(le[k]==re[k])
        {
            for(int i=1;i<=26;i++)
                if(num[k][i])
                {
                    ans[++len]=i-1+'a';
                    return ;
                }
        }
        if(lz[k])down(k);
        cacl(ls(k));
        cacl(rs(k));
    }
    int main()
    {
        n=read();m=read();
        scanf("%s",str+1);
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            int l=read(),r=read(),op=read();
            memset(res,0,sizeof(res));
            query(1,l,r);
            if(op)
            {
                for(int j=1;j<=26;j++)
                    if(res[j])
                        change(1,l,l+res[j]-1,j),l+=res[j];
            }
            else
            {
                for(int j=26;j>=1;j--)
                    if(res[j])
                        change(1,l,l+res[j]-1,j),l+=res[j];
            }
        }
        cacl(1);
        printf("%s
    ",ans+1);
        return 0;
    }

    丧心病狂科学打表的循环展开代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define rint  register int
    using namespace std;
    const int N=100005;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    int n,m,len;
    char str[N],ans[N];
    #define ls(k) k<<1
    #define rs(k) k<<1|1
    int num[N<<2][28],lz[N<<2],le[N<<2],re[N<<2];
    int res[28];
    void up(int k)
    {
                                     num[k][1]=num[ls(k)][1]+num[rs(k)][1];
                         num[k][2]=num[ls(k)][2]+num[rs(k)][2];
                                                     num[k][3]=num[ls(k)][3]+num[rs(k)][3];
                      num[k][4]=num[ls(k)][4]+num[rs(k)][4];
                                                              num[k][5]=num[ls(k)][5]+num[rs(k)][5];
                          num[k][6]=num[ls(k)][6]+num[rs(k)][6];
                                                                       num[k][7]=num[ls(k)][7]+num[rs(k)][7];
                                  num[k][8]=num[ls(k)][8]+num[rs(k)][8];
          num[k][9]=num[ls(k)][9]+num[rs(k)][9];
                                          num[k][10]=num[ls(k)][10]+num[rs(k)][10];
                                                                     num[k][11]=num[ls(k)][11]+num[rs(k)][11];
                                              num[k][12]=num[ls(k)][12]+num[rs(k)][12];
                                          num[k][13]=num[ls(k)][13]+num[rs(k)][13];
                                                                              num[k][14]=num[ls(k)][14]+num[rs(k)][14];
                                     num[k][15]=num[ls(k)][15]+num[rs(k)][15];
                                                                  num[k][16]=num[ls(k)][16]+num[rs(k)][16];
                             num[k][17]=num[ls(k)][17]+num[rs(k)][17];
                                                 num[k][18]=num[ls(k)][18]+num[rs(k)][18];
                                                                         num[k][19]=num[ls(k)][19]+num[rs(k)][19];
                  num[k][20]=num[ls(k)][20]+num[rs(k)][20];
                                                                      num[k][21]=num[ls(k)][21]+num[rs(k)][21];
                                      num[k][22]=num[ls(k)][22]+num[rs(k)][22];
              num[k][23]=num[ls(k)][23]+num[rs(k)][23];
                                                                     num[k][24]=num[ls(k)][24]+num[rs(k)][24];
                                  num[k][25]=num[ls(k)][25]+num[rs(k)][25];
                                     num[k][26]=num[ls(k)][26]+num[rs(k)][26];
    }
    void build(int k,int l,int r)
    {
        lz[k]=0;le[k]=l,re[k]=r;
        if(l==r)
        {
            num[k][str[l]-'a'+1]=1;
            return ;
        }
        int mid=l+r>>1;
        build(ls(k),l,mid);
        build(rs(k),mid+1,r);
        up(k);
    }
    void down(int k)
    {
        memset(num[ls(k)],0,sizeof(num[ls(k)]));
        memset(num[rs(k)],0,sizeof(num[rs(k)]));
        num[ls(k)][lz[k]]=re[ls(k)]-le[ls(k)]+1;
        num[rs(k)][lz[k]]=re[rs(k)]-le[rs(k)]+1;
        lz[ls(k)]=lz[rs(k)]=lz[k];
        lz[k]=0;
    }
    void query(int k,int L,int R)
    {
        if(le[k]>=L&&R>=re[k])
        {
                                                                    res[1]+=num[k][1];
                                                        res[2]+=num[k][2];
                res[3]+=num[k][3];
                            res[4]+=num[k][4];
                            res[5]+=num[k][5];
                res[6]+=num[k][6];
                                res[7]+=num[k][7];
                                        res[8]+=num[k][8];
                    res[9]+=num[k][9];
                                        res[10]+=num[k][10];
                            res[11]+=num[k][11];
                                                    res[12]+=num[k][12];
                        res[13]+=num[k][13];
                                                                res[14]+=num[k][14];
                                    res[15]+=num[k][15];
                                                    res[16]+=num[k][16];
                                                res[17]+=num[k][17];
                                                            res[18]+=num[k][18];
                                    res[19]+=num[k][19];
                                                res[20]+=num[k][20];
                    res[21]+=num[k][21];
            res[22]+=num[k][22];
                        res[23]+=num[k][23];
                                            res[24]+=num[k][24];
                                                                res[25]+=num[k][25];
                                        res[26]+=num[k][26];
            return ;
        }
        int mid=le[k]+re[k]>>1;
        if(lz[k])down(k);
        if(L<=mid)query(ls(k),L,R);
        if(R>mid)query(rs(k),L,R);
    }
    void change(int k,int L,int R,int val)
    {
        if(le[k]>=L&&R>=re[k])
        {
            memset(num[k],0,sizeof(num[k]));
            num[k][val]=re[k]-le[k]+1;
            lz[k]=val;
            return ;
        }
        int mid=le[k]+re[k]>>1;
        if(lz[k])down(k);
        if(L<=mid)change(ls(k),L,R,val);
        if(R>mid)change(rs(k),L,R,val);
        up(k);
    }
    void cacl(int k)
    {
        if(le[k]==re[k])
        {
            if(num[k][1]){ans[++len]=1-1+'a';return ;}
                            if(num[k][2]){ans[++len]=2-1+'a';return ;}
                    if(num[k][3]){ans[++len]=3-1+'a';return ;}
                                if(num[k][4]){ans[++len]=4-1+'a';return ;}
                                            if(num[k][5]){ans[++len]=5-1+'a';return ;}
        if(num[k][6]){ans[++len]=6-1+'a';return ;}
                    if(num[k][7]){ans[++len]=7-1+'a';return ;}
                                        if(num[k][8]){ans[++len]=8-1+'a';return ;}
                                                if(num[k][9]){ans[++len]=9-1+'a';return ;}
        if(num[k][10]){ans[++len]=10-1+'a';return ;}
                                            if(num[k][11]){ans[++len]=11-1+'a';return ;}
                            if(num[k][12]){ans[++len]=12-1+'a';return ;}
        if(num[k][13]){ans[++len]=13-1+'a';return ;}
        if(num[k][14]){ans[++len]=14-1+'a';return ;}
                if(num[k][15]){ans[++len]=15-1+'a';return ;}
                            if(num[k][16]){ans[++len]=16-1+'a';return ;}
                                        if(num[k][17]){ans[++len]=17-1+'a';return ;}
        if(num[k][18]){ans[++len]=18-1+'a';return ;}
                                    if(num[k][19]){ans[++len]=19-1+'a';return ;}
                            if(num[k][20]){ans[++len]=20-1+'a';return ;}
                                                        if(num[k][21]){ans[++len]=21-1+'a';return ;}
                                if(num[k][22]){ans[++len]=22-1+'a';return ;}
                    if(num[k][23]){ans[++len]=23-1+'a';return ;}
        if(num[k][24]){ans[++len]=24-1+'a';return ;}
                if(num[k][25]){ans[++len]=25-1+'a';return ;}
                                        if(num[k][26]){ans[++len]=26-1+'a';return ;}
        }
        if(lz[k])down(k);
        cacl(ls(k));
        cacl(rs(k));
    }
    int main()
    {
        n=read();m=read();
        scanf("%s",str+1);
        build(1,1,n);
        for(rint i=1;i<=m;i++)
        {
            int l=read(),r=read(),op=read();
            memset(res,0,sizeof(res));
            query(1,l,r);
            if(op)
            {
                            if(res[1])change(1,l,l+res[1]-1,1),l+=res[1];
                        if(res[2])change(1,l,l+res[2]-1,2),l+=res[2];
                                    if(res[3])change(1,l,l+res[3]-1,3),l+=res[3];
                        if(res[4])change(1,l,l+res[4]-1,4),l+=res[4];
                                                    if(res[5])change(1,l,l+res[5]-1,5),l+=res[5];
                            if(res[6])change(1,l,l+res[6]-1,6),l+=res[6];
                                                if(res[7])change(1,l,l+res[7]-1,7),l+=res[7];
                                if(res[8])change(1,l,l+res[8]-1,8),l+=res[8];
                                                        if(res[9])change(1,l,l+res[9]-1,9),l+=res[9];
                            if(res[10])change(1,l,l+res[10]-1,10),l+=res[10];
                                                if(res[11])change(1,l,l+res[11]-1,11),l+=res[11];
                                if(res[12])change(1,l,l+res[12]-1,12),l+=res[12];
                                                    if(res[13])change(1,l,l+res[13]-1,13),l+=res[13];
                                    if(res[14])change(1,l,l+res[14]-1,14),l+=res[14];
                                                        if(res[15])change(1,l,l+res[15]-1,15),l+=res[15];
                    if(res[16])change(1,l,l+res[16]-1,16),l+=res[16];
                                    if(res[17])change(1,l,l+res[17]-1,17),l+=res[17];
                                            if(res[18])change(1,l,l+res[18]-1,18),l+=res[18];
                        if(res[19])change(1,l,l+res[19]-1,19),l+=res[19];
                                                    if(res[20])change(1,l,l+res[20]-1,20),l+=res[20];
                            if(res[21])change(1,l,l+res[21]-1,21),l+=res[21];
                                                        if(res[22])change(1,l,l+res[22]-1,22),l+=res[22];
                            if(res[23])change(1,l,l+res[23]-1,23),l+=res[23];
                                            if(res[24])change(1,l,l+res[24]-1,24),l+=res[24];
                    if(res[25])change(1,l,l+res[25]-1,25),l+=res[25];
                                       if(res[26])change(1,l,l+res[26]-1,26),l+=res[26];
            }
            else
            {
                                    if(res[26])change(1,l,l+res[26]-1,26),l+=res[26];
            if(res[25])change(1,l,l+res[25]-1,25),l+=res[25];
                                                if(res[24])change(1,l,l+res[24]-1,24),l+=res[24];
                        if(res[23])change(1,l,l+res[23]-1,23),l+=res[23];
                                            if(res[22])change(1,l,l+res[22]-1,22),l+=res[22];
                if(res[21])change(1,l,l+res[21]-1,21),l+=res[21];
                                            if(res[20])change(1,l,l+res[20]-1,20),l+=res[20];
          if(res[19])change(1,l,l+res[19]-1,19),l+=res[19];
                                            if(res[18])change(1,l,l+res[18]-1,18),l+=res[18];
                                if(res[17])change(1,l,l+res[17]-1,17),l+=res[17];
                                                        if(res[16])change(1,l,l+res[16]-1,16),l+=res[16];
                            if(res[15])change(1,l,l+res[15]-1,15),l+=res[15];
                                                if(res[14])change(1,l,l+res[14]-1,14),l+=res[14];
                                            if(res[13])change(1,l,l+res[13]-1,13),l+=res[13];
                                if(res[12])change(1,l,l+res[12]-1,12),l+=res[12];
                                                            if(res[11])change(1,l,l+res[11]-1,11),l+=res[11];
                                            if(res[10])change(1,l,l+res[10]-1,10),l+=res[10];
                                        if(res[9])change(1,l,l+res[9]-1,9),l+=res[9];
                                if(res[8])change(1,l,l+res[8]-1,8),l+=res[8];
                        if(res[7])change(1,l,l+res[7]-1,7),l+=res[7];
                                            if(res[6])change(1,l,l+res[6]-1,6),l+=res[6];
                                    if(res[5])change(1,l,l+res[5]-1,5),l+=res[5];
                                                if(res[4])change(1,l,l+res[4]-1,4),l+=res[4];
                                            if(res[3])change(1,l,l+res[3]-1,3),l+=res[3];
           if(res[2])change(1,l,l+res[2]-1,2),l+=res[2];
                                if(res[1])change(1,l,l+res[1]-1,1),l+=res[1];
            }
        }
        cacl(1);
        printf("%s
    ",ans+1);
        return 0;
    }

    B.matrix

    神dp。状态数组我估计一辈子都想不出来。

    (虽然题意不明 似乎默认限制区间外必填0?)

    我们把构造矩阵的过程看作往矩阵里填1的过程,设$f[i][j]$为填到第i列,有j个1在右侧限制区间里的方案数。

    设$lnum[i]$为到i列时已结束的左限制区间的个数,$rnum[i]$为到i列时已开始的右限制区间的个数。

    转移时左右区间分别考虑:

    对于右区间,考虑到i列放与不放即可。如果不放的话就直接继承状态,即$f[i][j]+=f[i-1][j]$.如果放,则有$f[i][j+1]+=f[i-1][j]*(rnum[i]-j)$,解释一下:放1肯定得在已开始的右区间里放,但是还要除去已经放了的j个右区间。

    对于左区间,我们只在恰好经过它的结束点时对它进行考虑。既然有j个1放在右限制区间,已经转移了i列,那么一定有i-j个1放在左限制区间,毕竟每列只放一个。又因为有$lnum[i-1]$个左区间已经结束并处理过了,所以留给恰在第i列结束的左区间的1只有$i-j-lnum[i-1]$个(当然,这些1也可以放在之前的某一列里),那么对方案的贡献就要乘上$A_{i-j-lnum[i-1]}^{lnum[i]-lnum[i-1]}$了。

    排列数打表或逆元求皆可。

    //dp[i][j]:到第i列,j个1在各行的右区间
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=3005;
    const ll mod=998244353;
    int L[N],R[N],numl[N],numr[N],n,m;
    ll dp[N][N],A[N][N];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&L[i],&R[i]);
            numl[L[i]]++;numr[R[i]]++;
        }
        for(int i=1;i<=m;i++)
            numl[i]+=numl[i-1],numr[i]+=numr[i-1];
        for(int i=1;i<=m;i++)
        {
            A[i][0]=1;
            for(int j=1;j<=i;j++)
                A[i][j]=A[i][j-1]*1LL*(i-j+1)%mod;
        }
        dp[1][0]=1;A[0][0]=1;
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<=n;j++)
            {
                if(i-j-numl[i-1]<numl[i]-numl[i-1])//左:在这一列结束的左区间能放几个1
                {
                    dp[i][j]=0;
                    continue;
                }
                (dp[i][j]*=A[i-j-numl[i-1]][numl[i]-numl[i-1]])%=mod;
                (dp[i+1][j]+=dp[i][j])%=mod;
                (dp[i+1][j+1]+=dp[i][j]*1LL*(numr[i+1]-j))%=mod;
            //    cout<<dp[i][j]<<endl;
            }
        }
        cout<<dp[m][n]<<endl;
        return 0;
    }

    C.

    sb对手干的破事其实就是循环左移(最靠前的一位挪到后面,剩下全体左移一位)

    异或满足交换律结合律,那么就可以先利用前后缀求出每次除了初值外的异或和,将它们插入一棵01Trie,并通过对它进行dfs得出结果。

    如果儿子只有一个,我们选x时就能取与它相反的一位从而让这位成为1,所以在计答案时这一位为1;如果儿子有两个,不论我们这位选0还是1,对手都会取相同的一位使这一位成为0,所以答案中这一位只能为0。

    复杂度$O(nm)$

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    const int N=100005;
    int a[N],trie[N*26][3],xors[N],sxor[N];
    int tot,ans,ansnum,n,m;
    void ins(int num)
    {
        int root=0;
        for(int i=n-1;i>=0;i--)
        {
            int x=(num>>i)&1;
            if(!trie[root][x])trie[root][x]=++tot;
            root=trie[root][x];
        }
    }
    void dfs(int x,int val,int pos)
    {
        if(pos==1)
        {
            if(val>ans)ans=val,ansnum=1;
            else if(val==ans)ansnum++;
            return ;
        }
        if(!trie[x][0]||!trie[x][1])dfs(trie[x][0]+trie[x][1],val|(pos>>1),pos>>1);
        else dfs(trie[x][0],val,pos>>1),dfs(trie[x][1],val,pos>>1);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)scanf("%d",&a[i]);
        sxor[1]=a[1];
        for(int i=2;i<=m;i++)
            sxor[i]=sxor[i-1]^a[i];
        xors[m]=a[m];
        for(int i=m-1;i>=1;i--)
            xors[i]=xors[i+1]^a[i];
        for(int i=0;i<=m;i++)
            ins(xors[i+1]^(((sxor[i]<<1)/(1<<n)+(sxor[i]<<1))%(1<<n)));
        dfs(0,0,1<<n);
        cout<<ans<<endl<<ansnum<<endl;
        return 0;
    }

    UPD:之前说T3那个式子叫逻辑左移?不对不对,被亚历克斯鹅科普了一下,应该是循环左移(意会为主好吧)。

  • 相关阅读:
    requests模块
    Html5五子棋
    html5学习之旅第一篇
    Vue.js学习和第一个实例
    electron安装到第一个实例
    mongodb学习-练习实例
    nosql学习一
    csv内存流文件流
    关于Vue中img的src属性绑定的一些坑
    java中的==操作符和equals函数
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11288573.html
Copyright © 2011-2022 走看看