zoukankan      html  css  js  c++  java
  • Nowcoder 提高组练习赛-R1

      https://www.nowcoder.com/acm/contest/172#question

      单人报名300元,五人合报免费,于是就和学弟同学学长们组了一个三世同堂的队伍,高一的学长wzhqwq;同一届的同学们:zutter,asuldb;以及不是学长却胜似学长的qwaszx。

      感觉这套题比NOIP还是要难一些的。

      A:中位数:https://www.nowcoder.com/acm/contest/172/A

      题意概述:给定一个长度为$n$的序列,求它的所有长度大于等于$len$的子序列的中位数的最大值。$n,len<=10^5$

      NOIP的D1T1不应该是签到题吗...?这个题非常清奇啊。想了半小时(中间电脑死机2次)之后发现自己确实不会做,就写了一个$O(N^2logN)$的对顶堆做法,拿分倒是非常稳,确实得了60。

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <queue>
     4 # define R register int
     5  
     6 using namespace std;
     7  
     8 const int maxn=100005;
     9 int n,len,ans=0;
    10 int a[maxn];
    11 priority_queue <int,vector<int> > q1;
    12 priority_queue <int,vector<int>,greater<int> > q2;
    13  
    14 int read()
    15 {
    16     int x=0,f=1;
    17     char c=getchar();
    18     while (!isdigit(c)) { if(c=='-') f=-f; c=getchar(); }
    19     while (isdigit(c))  { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
    20     return x*f;
    21 }
    22  
    23 int ask()
    24 {
    25     if(q1.size()<q2.size())
    26         return q2.top();
    27     return q1.top();
    28 }
    29  
    30 int main()
    31 {
    32     n=read(),len=read();
    33     for (R i=1;i<=n;++i)
    34         a[i]=read();
    35     for (R i=1;i<=n;++i)
    36     {
    37         if(i+len-1>n) break;
    38         while (q1.size()) q1.pop();
    39         while (q2.size()) q2.pop();
    40         q1.push(-1000000009);
    41         q2.push(1000000009);
    42         for (R j=i;j<=n;++j)
    43         {
    44             if(a[j]<q2.top()) q1.push(a[j]);
    45             else q2.push(a[j]);
    46             while (q1.size()<q2.size())
    47             {
    48                 q1.push(q2.top());
    49                 q2.pop();
    50             }
    51             while (q2.size()<q1.size())
    52             {
    53                 q2.push(q1.top());
    54                 q1.pop();
    55             }
    56             if(j-i+1>=len) ans=max(ans,ask());
    57         }
    58     }
    59     printf("%d",ans);
    60     return 0;
    61 }
    中位数(60pts)

      现在来说一下正解:虽然答案本身并不单调,然而有一个东西是显而易见非常单调的:设$f_x=[ans>=x]$,这是一个布尔函数,它是单调的。所以二分这个答案,接下来考虑怎么$check$。离散化,大于等于$x$的设置成$1$,小于$x$的设成$-1$,如果一段长度大于$len$的区间的和大于$0$,就说明$f_x=true$。注意这里一定不能写成大于等于,因为这个$x$不一定是这个序列中真实存在的数,如果比它大,比它小的数一样多,这时的中位数是有可能小于$x$的(偶数长度的序列取小一点的那个值)。接下来的问题是怎么判断是否有区间的和大于$0$,其实就是求一段长度大于等于len的区间的和的最大值,用类似于单调队列优化dp的思想即可,不过只需要维护一个最小值。

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <queue>
     4 # define R register int
     5 
     6 using namespace std;
     7 
     8 const int maxn=100005;
     9 int n,len,ans=0;
    10 int a[maxn],b[maxn];
    11 int s[maxn],minn[maxn],maxx=0;
    12 
    13 int read()
    14 {
    15     int x=0,f=1;
    16     char c=getchar();
    17     while (!isdigit(c)) { if(c=='-') f=-f; c=getchar(); }
    18     while (isdigit(c))  { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
    19     return x*f;    
    20 }
    21 
    22 bool check (int x)
    23 {
    24     for (R i=1;i<=n;++i)
    25         if(a[i]<x) b[i]=-1;
    26         else b[i]=1;
    27     for (R i=1;i<=n;++i)
    28         s[i]=s[i-1]+b[i];
    29     minn[1]=s[1];
    30     for (R i=2;i<=n;++i)
    31         minn[i]=min(minn[i-1],s[i]);
    32     for (R i=len;i<=n;++i)
    33         if(s[i]>minn[i-len]) 
    34             return true;
    35     return false;
    36 }
    37 
    38 int main()
    39 {
    40     n=read(),len=read();
    41     for (R i=1;i<=n;++i)
    42         a[i]=read(),maxx=max(maxx,a[i]);
    43     int mid,ans=1,l=1,r=maxx;
    44     while (l<=r)
    45     {
    46         mid=(l-r)/2+r;
    47         if(check(mid))
    48             ans=max(ans,mid),l=mid+1;
    49         else 
    50             r=mid-1;
    51     }
    52     printf("%d",ans);
    53     return 0;
    54 }
    中位数

      B.数数字:https://www.nowcoder.com/acm/contest/172/B

      题意概述:对于一个数$x$,定义$f_x$为$x$的各个数位的乘积。对于$L<=x<=R$,问有多少$x$满足,$L_1<=f_x<=R_1$。

      $0<=L,R,L_1,R_1 <= 10^18,L<=R,L_1<=R_1$

      暴力可以得好多分,如果注意特判l=0的情况就会有50分的好成绩,但是考试时忘了这种问题所以只有45。正解是分解质因数的数位dp。

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # define R register int
     4 
     5 using namespace std;
     6 
     7 int l,r,ll,rr,ans;
     8 int x,s;
     9 
    10 int read()
    11 {
    12     int x=0,f=1;
    13     char c=getchar();
    14     while (!isdigit(c)) { if(c=='-') f=-f; c=getchar(); }
    15     while (isdigit(c))  { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
    16     return x*f;    
    17 }
    18 
    19 int main()
    20 {
    21     scanf("%d%d%d%d",&l,&r,&ll,&rr);
    22     for (int i=l;i<=r;++i)
    23     {
    24         s=1;
    25         x=i;
    26         if(x==0) s=0;
    27         while (x)
    28         {
    29             s*=x%10;
    30             x/=10;
    31         }
    32         if(ll<=s&&s<=rr) ans++;
    33     }
    34     printf("%d",ans);
    35     return 0;
    36 }
    数数字(50pts)

      C.保护:https://www.nowcoder.com/acm/contest/172/C

      题意概述:给定一颗$n$个点的树,以及$m$条路径,多组询问:给出一组$u$,$k$,询问从u到根的路径上满足(从$u$到$p$的路径整体都被至少k条路径覆盖过)的深度最浅的点$p.n,m,q<=200000$

      解释一下,$u->p$路径被路径$x$覆盖当且仅当$u->p$这段路径上的每一条边都属于路径$x$.

      看到这道题就觉得非常像天天爱跑步。想到了一个最差能到$O(q*max(n,m))$的算法,只得了$40$。这个做法是这样的,对于每一条路径首先求出它的$lca$,用$n$个$vector$,在每条路径的两个端点分别$push$一个编号进去,在$lca$处$push$一个编号的相反数,表示从这里再往上就不再有这条路径了。如果一条$u->p$路径被路径$x$所覆盖,则$x$必然有一个端点在$u$的子树内,而且它的$lca$不能在$p$的子树内。这样首先从$u$点向下递归,用一个$bitset$作为桶,统计有哪些路径覆盖了点u,再向上爬,每走一步就把$lca$在这里的路径删除去掉,直到路径的数目小于$k$为止。 

      
      1 # include <cstdio>
      2 # include <iostream>
      3 # include <vector>
      4 # include <bitset>
      5 # define R register int
      6 
      7 using namespace std;
      8 
      9 const int maxn=200005;
     10 int q,u,k,n,m,x,y,lca[maxn],s[maxn],t[maxn],cnt,dep[maxn],F[maxn][20];
     11 int firs[maxn],h,ans;
     12 vector<int> v[maxn];
     13 bitset <maxn> T;
     14 struct edge
     15 {
     16     int too,nex;
     17 }g[maxn<<1];
     18 
     19 int read()
     20 {
     21     int x=0,f=1;
     22     char c=getchar();
     23     while (!isdigit(c)) { if(c=='-') f=-f; c=getchar(); }
     24     while (isdigit(c))  { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
     25     return x*f;    
     26 }
     27 
     28 void add (int x,int y)
     29 {
     30     g[++h].too=y;
     31     g[h].nex=firs[x];
     32     firs[x]=h;
     33 }
     34 
     35 void dfs (int x)
     36 {
     37     int j;
     38     for (R i=firs[x];i;i=g[i].nex)
     39     {
     40         j=g[i].too;
     41         if(dep[j]) continue;
     42         dep[j]=dep[x]+1;
     43         F[j][0]=x;
     44         for (R i=1;i<=19;++i)
     45             F[j][i]=F[ F[j][i-1] ][i-1];
     46         dfs(j);
     47     }
     48 }
     49 
     50 void dfs1 (int x)
     51 {
     52     int j,siz=v[x].size();
     53     for (R i=0;i<siz;++i)
     54         if(v[x][i]>0&&T[ v[x][i] ]==0) 
     55             cnt++,T[ v[x][i] ]=1;
     56     for (R i=firs[x];i;i=g[i].nex)
     57     {
     58         j=g[i].too;
     59         if(dep[j]<dep[x]) continue;
     60         dfs1(j);
     61     }
     62     if(x==u) return;
     63     for (R i=0;i<siz;++i)
     64         if(v[x][i]<0&&T[ -v[x][i] ]==1)
     65             cnt--,T[ -v[x][i] ]=0;    
     66 }
     67 
     68 inline int LCA (int x,int y)
     69 {
     70     if(dep[x]>dep[y]) swap(x,y);
     71     for (R i=19;i>=0;--i)
     72         if(dep[y]-(1<<i)>=dep[x]) y=F[y][i];
     73     if(x==y) return x;    
     74     for (R i=19;i>=0;--i)
     75         if(F[x][i]!=F[y][i]) x=F[x][i],y=F[y][i];
     76     return F[x][0];
     77 }
     78 
     79 void up (int x)
     80 {
     81     if(cnt<k) return ;
     82     ans=dep[u]-dep[x];
     83     int siz=v[x].size();
     84     for (R i=0;i<siz;++i)
     85         if(v[x][i]<0&&T[ -v[x][i] ]==1)
     86             cnt--,T[ -v[x][i] ]=0;
     87     up(F[x][0]);
     88 }
     89 
     90 int main()
     91 {
     92     scanf("%d%d",&n,&m);
     93     for (R i=1;i<n;++i)
     94     {
     95         x=read();
     96         y=read();
     97         add(x,y);
     98         add(y,x);
     99     }
    100     dep[1]=1;
    101     dfs(1);
    102     for (R i=1;i<=m;++i)
    103     {
    104         s[i]=read();
    105         t[i]=read();
    106         lca[i]=LCA(s[i],t[i]);
    107         v[ s[i] ].push_back(i);
    108         v[ t[i] ].push_back(i);
    109         v[ lca[i] ].push_back(-i);
    110     }
    111     scanf("%d",&q);
    112     for (R i=1;i<=q;++i)
    113     {
    114         T.reset();
    115         cnt=0,ans=0;
    116         u=read();
    117         k=read();
    118         dfs1(u);
    119         up(u);
    120         printf("%d
    ",ans);
    121     }
    122     return 0;
    123 }
    保护(40pts)

      

      最后放一张惨淡的成绩,下次要加油啦 (在nowcoder,享受一场上蓝的快乐)

    ---shzr

  • 相关阅读:
    Fault-Tolerant Virtual Machine 论文笔记
    Google File System 论文笔记
    Amazon Aurora 论文笔记
    MATLAB入门学习(二):分支语句和编程设计
    MATLAB入门学习(一):基础准备
    矩阵连乘问题
    合并排序 java
    生产者与消费者 代码实现 java
    图的封装(C++)
    二叉树的封装
  • 原文地址:https://www.cnblogs.com/shzr/p/9614207.html
Copyright © 2011-2022 走看看