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
    愿你在迷茫时,记起自己的珍贵。
  • 相关阅读:
    背水一战 Windows 10 (61)
    背水一战 Windows 10 (60)
    背水一战 Windows 10 (59)
    背水一战 Windows 10 (58)
    背水一战 Windows 10 (57)
    背水一战 Windows 10 (56)
    背水一战 Windows 10 (55)
    背水一战 Windows 10 (54)
    背水一战 Windows 10 (53)
    背水一战 Windows 10 (52)
  • 原文地址:https://www.cnblogs.com/casun547/p/11289091.html
Copyright © 2011-2022 走看看