• 2019 计蒜之道 复赛


    外教 Michale 变身大熊猫

    https://nanti.jisuanke.com/t/39611

    way1.

    对不同长度的lis建一颗线段树,用动态开点。
      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <string>
      5 #include <cmath>
      6 #include <algorithm>
      7 #include <iostream>
      8 using namespace std;
      9 #define ll long long
     10 #include <vector>
     11 
     12 const int maxn=5e5+10;
     13 const ll mod=998244353;
     14 
     15 int a[maxn],b[maxn];
     16 
     17 struct node
     18 {
     19     int l,r;
     20     ll sum;
     21 }tr[maxn*30];///可离散化把范围从1e9变为5e5(n)
     22 int be[maxn],num,maxg=5e5,maxv=1e9;
     23 
     24 ll tot[maxn],tot1[maxn],x[maxn],y[maxn],x1[maxn],y11[maxn];
     25 
     26 ll query(int ind,int l,int r,int x,int y)
     27 {
     28     if (x<=l && r<=y)
     29         return tr[ind].sum;
     30     int m=(l+r)>>1;
     31     ll sum=0;
     32     if (x<=m && tr[ind].l)
     33         sum=(sum+query(tr[ind].l,l,m,x,y))%mod;
     34     if (m<y && tr[ind].r)
     35         sum=(sum+query(tr[ind].r,m+1,r,x,y))%mod;
     36     return sum;
     37 }
     38 
     39 void update(int ind,int l,int r,int y,ll z)
     40 {
     41     if (l==r)
     42     {
     43         tr[ind].sum=(tr[ind].sum+z)%mod;
     44         return;
     45     }
     46     int m=(l+r)>>1;
     47     if (y<=m)
     48     {
     49         if (!tr[ind].l)
     50             tr[ind].l=++num;
     51         update(tr[ind].l,l,m,y,z);
     52     }
     53     else
     54     {
     55         if (!tr[ind].r)
     56             tr[ind].r=++num;
     57         update(tr[ind].r,m+1,r,y,z);
     58     }
     59     tr[ind].sum=(tr[tr[ind].l].sum + tr[tr[ind].r].sum)%mod;
     60 }
     61 
     62 ll mul(ll a,ll b)
     63 {
     64     ll y=1;
     65     while (b)
     66     {
     67         if (b & 1)
     68             y=y*a%mod;
     69         a=a*a%mod;
     70         b>>=1;
     71     }
     72     return y;
     73 }
     74 
     75 int main()
     76 {
     77     int n,i,j,l,r,m;
     78     ll v;
     79     scanf("%d",&n);
     80     for (i=1;i<=n;i++)
     81         scanf("%d",&a[i]);
     82 
     83     for (i=1;i<=maxg;i++)
     84         be[i]=++num;
     85 
     86     j=0;
     87     for (i=1;i<=n;i++)
     88     {
     89         l=1,r=j;
     90         while (l<=r)
     91         {
     92             m=(l+r)>>1;
     93             if (a[i]<=b[m])
     94                 r=m-1;
     95             else
     96                 l=m+1;
     97         }
     98         b[l]=a[i];
     99         if (l>j)
    100             j++;
    101 
    102         ///all >0
    103         if (l==1)
    104             v=1;
    105         else
    106             v=query(be[l-1],1,maxv,1,b[l]-1);
    107         update(be[l],1,maxv,b[l],v);
    108         tot[l]=(tot[l]+v)%mod;
    109         x[i]=l;
    110         y[i]=v;
    111     }
    112 //    printf("%lld",tot[j]);    ///求强制lis
    113 
    114 
    115     ///reverse
    116 
    117     for (i=1;i<=num;i++)
    118         tr[i].l=0,tr[i].r=0,tr[i].sum=0;
    119     num=0;
    120 
    121     for (i=1;i<=maxg;i++)
    122         be[i]=++num;
    123 
    124     j=0;
    125     for (i=n;i>=1;i--)
    126     {
    127         l=1,r=j;
    128         while (l<=r)
    129         {
    130             m=(l+r)>>1;
    131             if (a[i]>=b[m])
    132                 r=m-1;
    133             else
    134                 l=m+1;
    135         }
    136         b[l]=a[i];
    137         if (l>j)
    138             j++;
    139 
    140         ///all >0
    141         if (l==1)
    142             v=1;
    143         else
    144             v=query(be[l-1],1,maxv,b[l]+1,maxv);
    145         update(be[l],1,maxv,b[l],v);
    146 //        tot1[l]=(tot1[l]+v)%mod;
    147         x1[i]=l;
    148         y11[i]=v;
    149     }
    150 
    151     ll chu=mul(tot[j],mod-2);
    152 
    153     for (i=1;i<=n;i++)
    154     {
    155         if (i!=1)
    156             printf(" ");
    157         if (x[i]+x1[i]==j+1)
    158         {
    159             y[i]=y[i]*y11[i]%mod;
    160             printf("%lld",y[i]*chu%mod);
    161         }
    162         else
    163             printf("0");
    164     }
    165     return 0;
    166 }
    167 /*
    168 8
    169 6 5 6 7 1 2 2 3
    170 */

    way2.

    study from solution&群友

    树状数组。


    对于树状数组的f[x],它统计若干个数(加lowbit到达x的所有数)作为结尾的子序列为最大时的值和对应的数量,

    对于数字x是否会被f[x]一同统计的其它数(xx=x-lowbit(x),xxx=xx-lowbit(xx),...)覆盖,影响数字x作为最长子序列的一员,答案是不会。因为f[x]一同统计的其它数小于x,若以x为结尾的子序列为最大时的值小于这些数为结尾的子序列为最大时的值时,对于大于x的数,它选择衔接f[x]一同统计的某个其它数,子序列的数目必优于衔接x时的子序列的数目。

    e.g. 8 1 7 9

    对于f[x]一同统计的其它数是否会被数字x覆盖,影响f[x]一同统计的其它数作为最长子序列的一员,答案是不会。数字x是最新出现的,它衔接之前以小于x的数为结尾的子序列,f[x]一同统计的其它数(它们都小于x)为结尾的子序列必然不再是最长子序列,它们的结果被覆盖。对于位置在数字x之后的数,只有小于等于x的数y,衔接f[x]一同统计的其它数为结尾的子序列,才有可能与当前最长子序列的长度齐平,而对于y,它统计以[1,y-1]为结尾的子序列为最大时的值和对应的数量,x>=y-1,必然不会用到f[x]。

    e.g. 7 8 8

    感觉好拗口,实在是想不明白大佬们怎么想到会用树状数组做的。

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cmath>
      4 #include <cstring>
      5 #include <string>
      6 #include <algorithm>
      7 #include <iostream>
      8 using namespace std;
      9 #define ll long long
     10 
     11 const double eps=1e-8;
     12 const ll inf=1e9;
     13 const ll mod=998244353;
     14 const int maxn=5e5+10;
     15 
     16 struct node
     17 {
     18     int x;
     19     ll y;
     20 }f[maxn],f1[maxn],be[maxn],en[maxn];
     21 
     22 struct rec
     23 {
     24     int x,y;
     25     bool operator<(const rec &b) const
     26     {
     27         return x<b.x;
     28     }
     29 }b[maxn];
     30 
     31 int a[maxn];
     32 
     33 ll mul(ll a,ll b)
     34 {
     35     ll y=1;
     36     while (b)
     37     {
     38         if (b & 1)
     39             y=y*a%mod;
     40         a=a*a%mod;
     41         b>>=1;
     42     }
     43     return y;
     44 }
     45 
     46 int main()
     47 {
     48     int n,m=0,i,j,k,maxsiz=0;
     49     ll l,tot=0;
     50     scanf("%d",&n);
     51     for (i=1;i<=n;i++)
     52     {
     53         scanf("%d",&b[i].x);
     54         b[i].y=i;
     55     }
     56     sort(b+1,b+n+1);
     57     b[0].x=b[1].x-1;
     58     for (i=1;i<=n;i++)
     59     {
     60         if (b[i].x!=b[i-1].x)
     61             m++;
     62         a[b[i].y]=m;
     63     }
     64 
     65     for (i=1;i<=n;i++)
     66     {
     67         j=a[i]-1;
     68         k=0,l=0;
     69         while (j>=1)
     70         {
     71             if (k<f[j].x)
     72                 k=f[j].x,l=f[j].y;
     73             else if (k==f[j].x)
     74                 (l+=f[j].y)%=mod;
     75             j-=j&-j;
     76         }
     77         if (k==0)
     78             l++;
     79         k++;
     80         be[i]={k,l};
     81 
     82         if (k==maxsiz)
     83             (tot+=l)%=mod;
     84         else if (k>maxsiz)
     85             maxsiz=max(maxsiz,k),tot=l;
     86         j=a[i];
     87         while (j<=m)
     88         {
     89             if (k>f[j].x)
     90                 f[j].x=k,f[j].y=l;
     91             else if (k==f[j].x)
     92                 (f[j].y+=l)%=mod;
     93             j+=j&-j;
     94         }
     95     }
     96 
     97     for (i=n;i>=1;i--)
     98     {
     99         a[i]=m+1-a[i];
    100         j=a[i]-1;
    101         k=0,l=0;
    102         while (j>=1)
    103         {
    104             if (k<f1[j].x)
    105                 k=f1[j].x,l=f1[j].y;
    106             else if (k==f1[j].x)
    107                 (l+=f1[j].y)%=mod;
    108             j-=j&-j;
    109         }
    110         if (k==0)
    111             l++;
    112         k++;
    113         en[i]={k,l};
    114 
    115         j=a[i];
    116         while (j<=m)
    117         {
    118             if (k>f1[j].x)
    119                 f1[j].x=k,f1[j].y=l;
    120             else if (k==f1[j].x)
    121                 (f1[j].y+=l)%=mod;
    122             j+=j&-j;
    123         }
    124     }
    125 
    126     for (i=1;i<=n;i++)
    127         if (be[i].x+en[i].x==maxsiz+1)
    128             printf("%lld%c",be[i].y*en[i].y%mod*mul(tot,mod-2)%mod,(i==n)?'
    ':' ');
    129         else
    130             printf("0%c",(i==n)?'
    ':' ');
    131     return 0;
    132 }
    133 /*
    134 6
    135 1 4 3 2 1 2
    136 
    137 8
    138 6 5 6 7 1 2 2 3
    139 
    140 5
    141 2 5 4 1 3
    142 */

    “星云系统”

    https://nanti.jisuanke.com/t/39614

    way1.单调栈

    每个字符最多被加入和删除一次

    119ms

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <string>
     5 #include <cmath>
     6 #include <algorithm>
     7 #include <iostream>
     8 using namespace std;
     9 #define ll long long
    10 
    11 const int maxn=5e6+10;
    12 
    13 char str[maxn],p[maxn];
    14 int st[maxn];
    15 
    16 int main()
    17 {
    18     int g,len,i,j,k;
    19     scanf("%s%d",str,&g);
    20     len=strlen(str);
    21     j=0;
    22     for (i=0;i<len;i++)
    23     {
    24         k=max(g-len+i,0);
    25         while (j>k && str[i]<p[j-1])
    26             j--;
    27         p[j++]=str[i];
    28     }
    29     p[g]=0;
    30     printf("%s",p);
    31     return 0;
    32 }

    way2. 二分

    一个数插入到s[i]-s[j]的哪个位置

    时间复杂度为log(1)+log(2)+...+log(5e5),远没想象中大,大概一千万。

    213ms

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <string>
     5 #include <cmath>
     6 #include <algorithm>
     7 #include <iostream>
     8 using namespace std;
     9 #define ll long long
    10 
    11 const int maxn=5e6+10;
    12 
    13 char str[maxn],p[maxn],c;
    14 
    15 int main()
    16 {
    17     int g,len,x=1,y=0,l,r,m,i;
    18     scanf("%s%d",str,&g);
    19     len=strlen(str);
    20     for (i=0;i<len;i++)
    21     {
    22         if (len-i<g)
    23             x++;
    24         c=str[i];
    25         l=x,r=y;
    26         while (l<=r)
    27         {
    28             m=(l+r)>>1;
    29             if (c>=p[m])
    30                 l=m+1;
    31             else
    32                 r=m-1;
    33         }
    34         if (r==g+1)
    35             continue;
    36 
    37         if (x>y)
    38             r=x;
    39         else if (r<x || c>=p[r])
    40             r++;
    41         y=r;
    42         p[r]=str[i];
    43     }
    44     p[g+1]=0;
    45     printf("%s",p+1);
    46     return 0;
    47 }
    48 /*
    49 abcdef
    50 5
    51 
    52 bbcaaew
    53 5
    54 
    55 fffffaf
    56 5
    57 
    58 dbccca
    59 5
    60 
    61 azzz
    62 4
    63 
    64 d
    65 1
    66 
    67 dc
    68 2
    69 
    70 aaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbb
    71 25
    72 
    73 zddddddddddddddadfasf
    74 10
    75 */

    way3.序列自动机

    study from 群友

    对于目标子序列的每一位,找一个满足后续操作的最小的字符

    O(26N) 1.3e8

    但实际上,

    579ms,说明要么测试数据规模小,要么评测机快。。。

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <string>
     6 #include <algorithm>
     7 #include <iostream>
     8 using namespace std;
     9 #define ll long long
    10 
    11 const double eps=1e-8;
    12 const ll inf=1e9;
    13 const ll mod=1e9+7;
    14 const int maxn=5e6+10;
    15 
    16 char str[maxn];
    17 int w[26],g[26];
    18 vector<int> nex[26];
    19 
    20 int main()
    21 {
    22     int len,G,i,j,pos;
    23     scanf("%s",str);
    24     len=strlen(str);
    25     for (i=0;i<len;i++)
    26     {
    27         j=str[i]-97;
    28         g[j]++;
    29         nex[j].push_back(i);
    30     }
    31     scanf("%d",&G);
    32     for (i=0;i<26;i++)
    33         w[i]=0;///
    34 
    35     pos=0;
    36     while (G--)
    37     {
    38         for (i=0;i<26;i++)
    39         {
    40             while (w[i]!=g[i] && nex[i][w[i]]<pos)
    41                 w[i]++;
    42             if (w[i]!=g[i] && len-nex[i][w[i]]>=G+1)
    43                 break;
    44         }
    45         pos=nex[i][w[i]]+1;
    46         w[i]++;
    47         printf("%c",i+97);
    48     }
    49     return 0;
    50 }

    其中可以写成nex的形式,就可以不用vector了。

    一个优化的方法,却跑了更长的时间(估计跟获取vector数据慢有关)

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <string>
     6 #include <algorithm>
     7 #include <iostream>
     8 using namespace std;
     9 #define ll long long
    10 
    11 const double eps=1e-8;
    12 const ll inf=1e9;
    13 const ll mod=1e9+7;
    14 const int maxn=5e6+10;
    15 
    16 char str[maxn];
    17 int w[26],g[26];
    18 vector<int> nex[26];
    19 
    20 int main()
    21 {
    22     int len,G,i,j,pos,v;
    23     bool vis;
    24     scanf("%s",str);
    25     len=strlen(str);
    26     for (i=0;i<len;i++)
    27     {
    28         j=str[i]-97;
    29         g[j]++;
    30         nex[j].push_back(i);
    31     }
    32     scanf("%d",&G);
    33     for (i=0;i<26;i++)
    34         w[i]=0;///
    35 
    36     pos=0;
    37     while (G)
    38     {
    39         v=inf;
    40         for (i=0;i<26;i++)
    41         {
    42             vis=0;
    43             while (w[i]!=g[i] && nex[i][w[i]]<pos)
    44                 w[i]++;
    45             while (w[i]!=g[i] && len-nex[i][w[i]]>=G && nex[i][w[i]]<v)
    46             {
    47                 G--;
    48                 pos=nex[i][w[i]]+1;
    49                 w[i]++;
    50                 vis=1;
    51                 break;
    52             }
    53             if (vis)
    54                 break;
    55             if (w[i]!=g[i])
    56                 v=min(v,nex[i][w[i]]);
    57         }
    58         printf("%c",i+97);
    59     }
    60     return 0;
    61 }

    内存超限的代码(然后改为用vector)

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <string>
     6 #include <algorithm>
     7 #include <iostream>
     8 using namespace std;
     9 #define ll long long
    10 
    11 const double eps=1e-8;
    12 const ll inf=1e9;
    13 const ll mod=1e9+7;
    14 const int maxn=5e6+10;
    15 
    16 char str[maxn];
    17 int nex[26][maxn],w[26];
    18 
    19 int main()
    20 {
    21     int len,g,i,j,pos;
    22     scanf("%s",str);
    23     len=strlen(str);
    24     for (i=0;i<len;i++)
    25     {
    26         j=str[i]-97;
    27         nex[j][0]++;
    28         nex[j][nex[j][0]]=i;
    29     }
    30     scanf("%d",&g);
    31     for (i=0;i<26;i++)
    32         w[i]=1;
    33 
    34     pos=0;
    35     while (g--)
    36     {
    37         for (i=0;i<26;i++)
    38         {
    39             while (w[i]!=nex[i][0]+1 && nex[i][w[i]]<pos)
    40                 w[i]++;
    41             if (w[i]!=nex[i][0]+1 && len-nex[i][w[i]]>=g+1)
    42                 break;
    43         }
    44         pos=nex[i][w[i]]+1;
    45         w[i]++;
    46         printf("%c",i+97);
    47     }
    48     return 0;
    49 }
  • 相关阅读:
    According to TLD or attribute directive in tag file, attribute end does not accept any expressions
    Several ports (8080, 8009) required by Tomcat v6.0 Server at localhost are already in use.
    sql注入漏洞
    Servlet—简单的管理系统
    ServletContext与网站计数器
    VS2010+ICE3.5运行官方demo报错----std::bad_alloc
    java 使用相对路径读取文件
    shell编程 if 注意事项
    Ubuntu12.04下eclipse提示框黑色背景色的修改方法
    解决Ubuntu环境变量错误导致无法正常登录
  • 原文地址:https://www.cnblogs.com/cmyg/p/11166722.html
Copyright © 2020-2023  润新知