zoukankan      html  css  js  c++  java
  • 模拟11题解

    T1[A. string]「桶排序」「线段树」

    线段树维护区间的每个字母出现了多少次,

    在排序的时候,先查询一个区间的每个字母的出现次数,然后挨个区间赋值

    复杂度  $O(mlog(n)*26)$

    优化常数(26):定义f(懒标记):f!=0时,代表子树都被赋值为了同一个值;f==0,表示不相等。

    将区间查询改为只有访问到了f!=0再对ans贡献return,pushup,pushdown同理,避免了枚举26

    当然也可以循环展开勉强卡过

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #define mid ((t[k].l+t[k].r)>>1)
      6 #define lc (k<<1)
      7 #define rc (k<<1|1)
      8 #define R register
      9 using namespace std;
     10 int read()
     11 {
     12     int f=1,x=0;char ch=getchar();
     13     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
     14     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
     15     return f*x;
     16 }
     17 const int maxn=100005;
     18 struct node{
     19     int l,r,sum,f;
     20 }t[maxn*4];
     21 char s[maxn];
     22 int a[maxn],ans[30];
     23 inline void up(R int k)
     24 {
     25     if(t[lc].f==t[rc].f&&t[lc].f)  t[k].f=t[lc].f;
     26     else t[k].f=0;
     27 }
     28 inline void down(R int k)
     29 {
     30     t[lc].f=t[rc].f=t[k].f;
     31 }
     32 void build(R int k,R int l,R int r)
     33 {        
     34     t[k].l=l,t[k].r=r;
     35     if(l==r)
     36     {
     37         t[k].f=a[l];
     38         t[k].sum=1;
     39         return;
     40     }
     41     build(lc,l,mid);
     42     build(rc,mid+1,r);
     43     t[k].sum=t[lc].sum+t[rc].sum;
     44     up(k);
     45 }
     46 void query(R int k,R int l,R int r)
     47 {
     48     if(t[k].l>=l&&t[k].r<=r&&t[k].f)
     49     {
     50         ans[t[k].f]+=t[k].sum;
     51         return;
     52     }
     53     if(t[k].f)down(k);
     54     if(l<=mid)query(lc,l,r);
     55     if(r>mid)query(rc,l,r);
     56     up(k);
     57 }
     58 void change(R int k,R int l,R int r,R int w)
     59 {
     60     if(t[k].l>=l&&t[k].r<=r)
     61     {
     62         t[k].f=w;
     63         return;
     64     }
     65     if(t[k].f) down(k);
     66     if(l<=mid)change(lc,l,r,w);
     67     if(r>mid)change(rc,l,r,w);
     68     up(k);
     69 }
     70 void print(R int k)
     71 {
     72     if(t[k].l==t[k].r)
     73     {
     74         char ch=t[k].f+'a'-1;
     75         printf("%c",ch);
     76         return;
     77        }
     78     if(t[k].f)  down(k);
     79     print(lc);
     80     print(rc);
     81 }
     82 int main()
     83 {
     84  //  freopen("data","r",stdin);
     85     const int n=read(),m=read();
     86     scanf("%s",s+1);
     87     for(R int i=1;i<=n;++i)
     88         a[i]=s[i]-'a'+1;
     89     build(1,1,n);
     90     for(R int i=1;i<=m;++i)
     91     {
     92         R int l=read(),r=read(),x=read();    
     93         memset(ans,0,sizeof ans);
     94         query(1,l,r);
     95         if(x)
     96         {
     97             for(R int i=1;i<=26;++i)
     98                 if(ans[i])
     99                 {
    100                     change(1,l,l+ans[i]-1,i);
    101                     l=l+ans[i];
    102                 }
    103         }
    104         else
    105         {
    106             for(R int i=26;i>=1;--i)
    107                 if(ans[i])
    108                 {
    109                     change(1,l,l+ans[i]-1,i);
    110                     l=l+ans[i];
    111                 }
    112         }
    113     }
    114     print(1);
    115 }
    116 /*
    117 g++ 1.cpp -o 1
    118 ./1
    119 
    120 */
    View Code

    T2 [B. matrix]「动态规划--两没一毒」

    定义f[i][j]:从左向右到了第i列(也就是有了i个1能放),有j个一放在了右区间,

    l[i]:到i列为止,有多少行的左区间已经结束;   r[i]:到i列为止,有多少右区间已经开始;

    f[i][j]=f[i-1][j]+f[i-1][j-1]*(r[i]-(j-1));

       前者为不放,后者 是再多放一个,j-1是右区间已经放了j-1个,总共有r[i]个空

    f[i][j]要乘上:A(i-j-l[i-1],l[i]-l[i-1])  

      l[i]-l[i-1]是第i列的能放的空,i是总共能有的1的个数,j个放在了右区间,l[i-1]个一定要放在已经结束的i-1个左区间里,剩下的选出来去放在能放的空里

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define int long long
     6 using namespace std;
     7 const int maxn=3005;
     8 const int mod=998244353 ;
     9 int read()
    10 {
    11     int f=1,x=0;char ch=getchar();
    12     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    13     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    14     return f*x;
    15 }
    16 int n,m,l[maxn],r[maxn],f[3005][3005];
    17 signed main()
    18 {
    19 //    freopen("data","r",stdin);
    20     n=read(),m=read();
    21     for(int i=1;i<=n;i++)
    22     {
    23         int li=read(),ri=read();
    24         l[li]++,r[ri]++;
    25     }
    26     for(int i=1;i<=m;i++)
    27         l[i]=l[i-1]+l[i],r[i]=r[i-1]+r[i];
    28 //    for(int i=1;i<=m;i++)cout<<l[i]<<
    29     f[0][0]=1;
    30     for(int i=1;i<=m;i++)
    31     {
    32         f[i][0]=f[i-1][0];
    33         for(int j=1;j<=r[i];j++)
    34             f[i][j]=(f[i-1][j]+f[i-1][j-1]*(r[i]-j+1)%mod)%mod;
    35         for(int j=0;j<=min(i,n);j++)
    36             for(int k=l[i-1];k<=min(i-j,l[i]-1);k++)
    37                 f[i][j]=f[i][j]*(i-j-k)%mod;
    38     }    
    39     printf("%lld
    ",f[m][n]%mod);
    40 }
    41 /*
    42 g++ 1.cpp -o 1
    43 ./1
    44 
    45 */

    View Code

    T3[C. big]「trie树」

    性质:(a^b^c)<<d=(a<<d)^(b<<d)^(c<<d)

    性质:对手操作的原式等价与左移,(若2x<2^n相当与左移,反之就是逻辑左移)总之保证操作之后不会超过2^n

    所以断点i就是使1~i先都左移再求异或和

    处理一个前缀异或和sum,((x^sum[i])<<1)^(sum[m]^sum[i])=(x<<1)^(sum[i]<<1)^(sum[m]^sum[i])

             ((sum[m]^sum[i])是i+1~m的异或和)

    其中(x<<1)可以取到2^n中的所有数,对于最终结果没有影响,且不用求它,可忽略

    (sum[i]<<1)^(sum[m]^sum[i])将其放入trie树中,从高位向低位存,dfs求最大值,要尽量避开trie树上的点,

    trie上只有0或1是对ans的贡献为1,接着沿其递归

    但0,1都有时,我选1,对手会选0,我选0,对手会选1,所以对ans的贡献是0,分别搜下去

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #define int long long
     6 const int maxn=4000005;
     7 using namespace std;
     8 int read()
     9 {
    10     int f=1,x=0;char ch=getchar();
    11     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    12     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    13     return f*x;
    14 }
    15 int n,m,p,sum[maxn],a[maxn];
    16 int t[maxn][3],tot;
    17 inline int change(int x){return (2*x/p+2*x)%p;}
    18 void insert(int x)
    19 {
    20     int nxt=0;
    21     for(int i=n-1;i>=0;i--)
    22     {
    23         const int fl=(x&(1<<i))?1:0;
    24         if(!t[nxt][fl])  t[nxt][fl]=++tot;
    25         nxt=t[nxt][fl];
    26     }
    27 }
    28 int mx,cnt;
    29 void dfs(int x,int dep,int ans)
    30 {
    31     if(dep==-1)
    32     {
    33         if(ans>mx)mx=ans,cnt=1;
    34         else if(ans==mx)cnt++;
    35         return;
    36     }
    37     if(t[x][1]&&t[x][0])
    38     {
    39         dfs(t[x][0],dep-1,ans);
    40         dfs(t[x][1],dep-1,ans);
    41         return;
    42     }
    43     if(t[x][1])
    44         dfs(t[x][1],dep-1,ans^(1<<dep));
    45     else if(t[x][0])
    46         dfs(t[x][0],dep-1,ans^(1<<dep));
    47 }
    48 signed main()
    49 {
    50     //freopen("data","r",stdin);
    51     n=read(),m=read();p=(1<<n);
    52     for(int i=1;i<=m;i++){
    53         a[i]=read();
    54         sum[i]=sum[i-1]^a[i];
    55     }
    56     for(int i=0;i<=m;i++)
    57         insert(change(sum[i])^sum[m]^sum[i]);
    58     dfs(0,n-1,0);
    59     printf("%lld
    %lld
    ",mx,cnt);
    60 }
    61 /*
    62 g++ 3.cpp -o 3
    63 ./3
    64 
    65 */
    View Code
    愿你在迷茫时,记起自己的珍贵。
  • 相关阅读:
    HTTP状态代码
    安装mySQL数据库常见问题
    python3.6安装版本选择
    用连接池提高Servlet访问数据库的效率
    策略模式
    如何在vue项目中修改less变量,多主题项目解决方案
    【前端】vue项目 url中传递数组参数
    element date-picker默认值问题
    echart 折线图legend不显示的问题
    vue学习之父子组件通信两种方法
  • 原文地址:https://www.cnblogs.com/casun547/p/11289091.html
Copyright © 2011-2022 走看看