zoukankan      html  css  js  c++  java
  • 2020 省选模拟测试 Round #4 solution (20/02/03)

    【比赛链接】http://59.61.75.5:8018/contest/214

    A. Access

    【题意】求执行最多 $k$ 次 $LCT$ 的 $access$ 能得到的树形态数。

    【数据范围】$n leq 10^4.k leq 500$。

    【题解】

    考虑 $LCT$ 的性质,每个点最多只有一条重儿子边。

    显然执行 $k$ 次操作后,会产生 $k$ 条不同的重链。

    考虑树上背包。设 $f[u][x][0/1]$ 表示以 $u$ 为根的子树中有 $x$ 个点执行过一次操作, $u$ 是否执行过操作。直接转移即可。注意细节。

    效率 $O(nk)$。期望得分:100。

    【代码】

     1 #include<bits/stdc++.h>
     2 const int mod=998244353;
     3 long long f[10010][510][2],g[510][2];
     4 int siz[10010],n,k;
     5 std::vector<int> e[10010];
     6 inline void dfs ( int u,int fr )
     7 {
     8     siz[u]=1;f[u][0][0]=1;
     9     for ( int v:e[u] ) if ( v!=fr )
    10     {
    11         dfs(v,u);
    12         for ( int x=0;x<=siz[u]+siz[v] and x<=k;x++ ) g[x][0]=g[x][1]=0;
    13         for ( int x=0;x<=siz[u] and x<=k;x++ ) for ( int y=0;y<=siz[v] and x+y<=k;y++ )
    14         {
    15             (g[x+y+1][1]+=f[u][x][0]*f[v][y][0])%=mod;
    16             (g[x+y+(y?1:0)][0]+=f[u][x][0]*f[v][y][0])%=mod;
    17             (g[x+y+(y?1:0)][1]+=f[u][x][1]*f[v][y][0])%=mod;
    18             (g[x+y][0]+=f[u][x][0]*f[v][y][1])%=mod;
    19             (g[x+y][1]+=f[u][x][0]*f[v][y][1])%=mod;
    20             (g[x+y][1]+=f[u][x][1]*f[v][y][1])%=mod;
    21         }
    22         for ( int x=0;x<=siz[u]+siz[v] and x<=k;x++ ) f[u][x][0]=g[x][0],f[u][x][1]=g[x][1];
    23         siz[u]+=siz[v];
    24     }
    25     for ( int x=0;x<=siz[u] and x<=k;x++ ) g[x][0]=g[x][1]=0;
    26     for ( int x=0;x<=siz[u] and x<=k;x++ ) for ( int y=0;y<2;y++ ) (g[x][y]+=f[u][x][y])%=mod;
    27     for ( int x=0;x<=siz[u] and x<=k;x++ ) f[u][x][0]=g[x][0],f[u][x][1]=g[x][1];
    28 }
    29 signed main()
    30 {
    31     scanf("%d%d",&n,&k);
    32     for ( int i=1,u,v;i<n;i++ ) scanf("%d%d",&u,&v),e[u].push_back(v),e[v].push_back(u);
    33     dfs(1,0);long long ans=f[1][k][1];
    34     for ( int x=0;x<k;x++ ) (ans+=f[1][x][0]+f[1][x][1])%=mod;
    35     return !printf("%lld
    ",ans);
    36 }
    DTOJ4700

    B. Convolution

    【题意】求 $sumlimits_{i=1}^{n} sumlimits_{j=1}^{n} 2^{a_ia_j} mod 998244353$。

    【数据范围】$n leq 10^5,a_i leq 10^5$。

    【题解】

    显然转化为统计 $a_i$ 的贡献。设权值为 $x$ 的数有 $b_x$ 个。记权值的最大值为 $m$。

    考虑对式子进行转化,使式子化为 $sumlimits_{i=0}^{m} sumlimits_{j=0}^{m} f_i imes f_j imes g_{i+j}$ 的形式,以便 $NTT$ 优化。

    则有:

    $$egin{aligned} sumlimits_{i=0}^{m} sumlimits_{j=0}^{m} b_i imes b_j imes 2^{ij}  &= sumlimits_{i=0}^{m} sumlimits_{j=0}^{m} b_i imes b_j imes 2^{frac{1}{2}((i+j)^2-i^2-j^2)} \ &= sumlimits_{i=0}^{m} sumlimits_{j=0}^{m} frac{b_i}{sqrt{2}^{i^2}} imes frac{b_j}{sqrt{2}^{j^2}} imes sqrt{2}^{(i+j)^2}end{aligned}$$

    直接 $NTT$ 优化即可。

    效率 $O(m log m)(m=maxlimits_{1leq i leq n}{a_i})$。期望得分:100。

    【代码】

     1 #include<bits/stdc++.h>
     2 const int mod=998244353,sqr2=116195171;
     3 const int G=3,invG=332748118;
     4 const int maxn=600000+10;
     5 int n,A[maxn],t,Pow[maxn],rev[maxn],ans;
     6 inline int power ( int x,long long y )
     7 {
     8     int z=1;
     9     for ( ;y;y>>=1,x=1LL*x*x%mod ) if ( y&1 ) z=1LL*z*x%mod;
    10     return z;
    11 }
    12 inline void NTT ( int *a,int f )
    13 {
    14     for ( int i=0;i<t;i++ ) if ( i<rev[i] ) std::swap(a[i],a[rev[i]]);
    15     for ( int i=2;i<=t;i<<=1 )
    16     {
    17         int wn=power((~f)?G:invG,(mod-1)/i);
    18         for ( int j=0;j<t;j+=i )
    19         {
    20             int w=1;
    21             for ( int k=0;k<i/2;k++,w=1LL*w*wn%mod )
    22             {
    23                 int x=a[j+k],y=1LL*w*a[j+k+i/2]%mod;
    24                 a[j+k]=(x+y)%mod,a[j+k+i/2]=(x-y+mod)%mod;
    25             }
    26         }
    27     }
    28     if ( f==-1 )
    29     {
    30         int invt=power(t,mod-2);
    31         for ( int i=0;i<t;i++ ) a[i]=1LL*a[i]*invt%mod;
    32     }
    33 }
    34 signed main()
    35 {
    36     scanf("%d",&n);
    37     for ( int x;n--; ) scanf("%d",&x),A[x]++;
    38     for ( int i=0;i<=100000;i++ ) A[i]=1LL*A[i]*power(power(sqr2,1LL*i*i),mod-2)%mod;
    39     for ( t=1;t<=200000;t<<=1 ) ;
    40     for ( int i=0;i<t;i++ ) rev[i]=(rev[i>>1]>>1)|((i&1)?(t>>1):0);
    41     NTT(A,1);
    42     for ( int i=0;i<t;i++ ) A[i]=1LL*A[i]*A[i]%mod;
    43     NTT(A,-1);
    44     for ( int i=0;i<=200000;i++ ) ans=(ans+1LL*A[i]*power(sqr2,1LL*i*i))%mod;
    45     return !printf("%d
    ",ans);
    46 }
    DTOJ4701

    C. Gcd

    【题意】求 $sumlimits_{i=1}^n sumlimits_{j=i}^{n} [j-i+1 leq n-2] imes maxlimits_{p,q in [1,i)cup (j,n],p eq q}gcd(a_p,a_q)$,多组数据。

    【数据范围】$1 leq T leq 5, 1 leq n leq 2 imes 10^{5}, 1 leq a_{i} leq 2 imes 10^{5}$。

    【题解】

    考虑枚举 $gcd$。显然只有 $gcd$ 的倍数会对答案造成影响。

    假设 $gcd$ 倍数的位置分别为 $a_i(1 leq i leq p)$,则显然答案一定包含以下三种情况之一:

    ① $(a_1,a_2)$ ② $(a_1,a_n)$ ③ $(a_{n-1},a_n)$

    查询三次即可。用线段树维护每个点为左端点的时候最远删到了哪,以及还剩多少个区间没有被删即可。

    效率 $O(m ln m + mlog n)(m=maxlimits_{1 leq i leq n} a_i)$。期望得分:100。

    【代码】

      1 #include<bits/stdc++.h>
      2 inline int read ( void )
      3 {
      4     int x=0;char ch;
      5     while ( !isdigit(ch=getchar()) ) ;
      6     for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
      7     return x;
      8 }
      9 const int maxn=200000+10;
     10 int n,m=200000,a[maxn],pos[maxn];
     11 struct tree { long long sum;int min,max,num; } t[maxn<<2];
     12 #define ls (k<<1)
     13 #define rs (k<<1|1)
     14 #define mid ((l+r)>>1)
     15 inline void pushup ( int k )
     16 {
     17     int g[4]={t[ls].min,t[rs].min,t[ls].max,t[rs].max};
     18     std::sort(g,g+4);t[k].min=g[0];t[k].num=0;
     19     if ( t[k].min==t[ls].min ) t[k].num+=t[ls].num;
     20     if ( t[k].min==t[rs].min ) t[k].num+=t[rs].num;
     21     for ( int i=1;i<4;i++ ) if ( g[i]!=g[0] ) { t[k].max=g[i];break; }
     22     t[k].sum=t[ls].sum+t[rs].sum;
     23 }
     24 inline void build ( int k,int l,int r )
     25 {
     26     t[k].sum=0;
     27     if ( l==r ) { t[k].sum=l;t[k].min=l;t[k].max=n+2;t[k].num=1;return; }
     28     build(ls,l,mid);build(rs,mid+1,r);pushup(k);
     29 }
     30 inline void pushdown ( int k )
     31 {
     32     int p=t[k].min;
     33     if ( t[ls].min<p ) t[ls].sum+=1LL*(p-t[ls].min)*t[ls].num,t[ls].min=p;
     34     if ( t[rs].min<p ) t[rs].sum+=1LL*(p-t[rs].min)*t[rs].num,t[rs].min=p;
     35 }
     36 inline long long query ( int k,int l,int r,int ql,int qr )
     37 {
     38     if ( ql<=l and r<=qr ) return t[k].sum;
     39     pushdown(k);
     40     if ( qr<=mid ) return query(ls,l,mid,ql,qr);
     41     if ( ql>mid ) return query(rs,mid+1,r,ql,qr);
     42     return query(ls,l,mid,ql,qr)+query(rs,mid+1,r,ql,qr);
     43 }
     44 inline void update ( int k,int l,int r,int ql,int qr,int p )
     45 {
     46     if ( ql<=l and r<=qr )
     47     {
     48         if ( t[k].min>=p ) return;
     49         if ( t[k].max>p or l==r ) { t[k].sum+=1LL*(p-t[k].min)*t[k].num,t[k].min=p;return; }
     50     }
     51     pushdown(k);
     52     if ( ql<=mid ) update(ls,l,mid,ql,qr,p);
     53     if ( qr>mid ) update(rs,mid+1,r,ql,qr,p);
     54     pushup(k);
     55 }
     56 inline int find ( int k,int l,int r,int p )
     57 {
     58     if ( l==r ) return (t[k].min>p)?l:(n+1);
     59     pushdown(k);
     60     if ( t[rs].min>p ) return std::min(find(ls,l,mid,p),mid+1);
     61     else return find(rs,mid+1,r,p);
     62 }
     63 #undef ls
     64 #undef rs
     65 #undef mid
     66 inline long long solve ( int l,int r )
     67 {
     68     if ( l>r ) return 0;
     69     int p=std::max(find(1,1,n,r),l);
     70     long long res=(p>l)?query(1,1,n,l,p-1):0;
     71     update(1,1,n,l,r,r+1);
     72     return 1LL*(p-l)*(r+1)-res;
     73 }
     74 signed main()
     75 {
     76     for ( int T=read();T--; )
     77     {
     78         n=read();build(1,1,n);m=0;
     79         for ( int i=1;i<=n;i++ ) m=std::max(m,a[i]=read());
     80         for ( int i=1;i<=m;i++ ) pos[i]=0;
     81         for ( int i=1;i<=n;i++ ) pos[a[i]]=i;
     82         long long ans=0;
     83         for ( int i=m;i;i-- )
     84         {
     85             std::vector<int> G;
     86             int min1=n+1,min2=n+1,max1=0,max2=0;
     87             for ( int j=i;j<=m;j+=i ) if ( pos[j] ) G.push_back(pos[j]);
     88             for ( int x:G )
     89             {
     90                 if ( x>max1 ) max2=max1,max1=x;
     91                 else if ( x>max2 ) max2=x;
     92                 if ( x<min1 ) min2=min1,min1=x;
     93                 else if ( x<min2 ) min2=x;
     94             }
     95             ans=ans+i*(solve(min1+1,max1-1)+solve(min2+1,n)+solve(1,max2-1));
     96         }
     97         printf("%lld
    ",ans);
     98     }
     99     return 0;
    100 }
    DTOJ4702
  • 相关阅读:
    virtualbox结合nat和host-only设置固定ip的环境
    [zebra源码]流控设计
    [zebra源码]JdbcFilter过滤器和SPI扩展
    [zebra源码]如果数据库连接建立失败会怎样
    [zebra源码]insert后获取自增值的处理
    [zebra源码]GroupDataSource读库的负载均衡
    [zebra源码]不带分片键的sql会怎么执行?
    [zebra源码]如果定位到多个分库或分表怎么执行的?
    自定义类型hash
    spark on dataworks
  • 原文地址:https://www.cnblogs.com/RenSheYu/p/12257500.html
Copyright © 2011-2022 走看看