zoukankan      html  css  js  c++  java
  • 省选模拟6 题解

    A. Yist

    首先考虑怎样的情况答案是不收敛的。

    操作中涉及到对一个权值非$0$,并且不作除法的点的加法贡献。

    因为只要最终的答案,可以想到对每个点作为出边的贡献分别处理。

    部分分提示求出第一次迭代的贡献,发现对于每个点,贡献都是一个等比数列,所以只要代入求和公式就好了。

    然而暴力做的复杂度是$O(mk)$的,会被菊花图的数据卡掉。

    考虑如何优化这个东西,根据套路我们将点按照度数分块。

    定义度数大于$sqrt m$的点为重点,度数小于等于$sqrt m$的点为轻点。

    分别讨论:

    对于对轻点的操作,因为度数并不大,可以直接暴力。

    对于重点的重出边,因为重点个数并不多,可以直接暴力。

    对于重点的轻出边,考虑打标记表示这个重点到连接的所有轻点进行了更新操作,修改轻点之前(以及所有操作进行完之后)需要扫重点以累计这个答案。

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 const int mod=998244353;
     5 const int N=2e5+7;
     6 const int inv2=499122177;
     7 int n,m,k,tot;
     8 bool vis[N];
     9 int s[N],head[N],nxt[N],to[N],d[N],sz[N],flag[N];
    10 ll sum[N],tim[N],w[N],t[N];
    11 inline void add(int a,int b){
    12     nxt[++tot]=head[a]; to[head[a]=tot]=b;
    13     nxt[++tot]=head[b]; to[head[b]=tot]=a;
    14     ++d[a]; ++d[b];
    15 }
    16 inline ll qpow(ll x,int k,ll r=1){
    17     for(;k;k>>=1,x=x*x%mod) if(k&1) r=r*x%mod;
    18     return r;
    19 }
    20 vector<int> g[N];//与i临接的重点
    21 inline int read(register int x=0,register char ch=getchar(),register int f=0){
    22     for(;!isdigit(ch);ch=getchar()) f=ch=='-';
    23     for(; isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
    24     return f?-x:x;
    25 }
    26 int main(){
    27     while(scanf("%d%d%d",&n,&m,&k)==3){
    28         const int sq=sqrt(n)+1; tot=0;
    29         memset(vis,0,sizeof(vis));
    30         memset(head,0,sizeof(head));
    31         memset(d,0,sizeof(d));
    32         memset(sz,0,sizeof(sz));
    33         memset(flag,0,sizeof(flag));
    34         memset(sum,0,sizeof(sum));
    35         for(int i=1;i<=n;++i) t[i]=w[i]=read(),tim[i]=1,g[i].clear();
    36         for(int i=1;i<=k;++i) s[i]=read();
    37         for(int i=1;i<=m;++i) add(read(),read());
    38         for(int i=1;i<=n;++i) if(d[i]>=sq) vis[i]=1;
    39         for(int i=1;i<=n;++i) for(int j=head[i];j;j=nxt[j]) if(vis[to[j]]) g[i].push_back(to[j]);
    40         for(int o=1;o<=k;++o){
    41             int x=s[o];
    42             if(vis[x]){
    43                 for(auto to:g[x]) sum[to]+=t[to];
    44                 ++flag[x];
    45                 tim[x]=tim[x]*inv2%mod;
    46                 t[x]=t[x]*inv2%mod;
    47             }
    48             else{
    49                 for(int i=head[x];i;i=nxt[i]){
    50                     if(vis[to[i]]&&sz[i]<flag[to[i]]) sum[x]+=t[x]*(flag[to[i]]-sz[i]),sz[i]=flag[to[i]];
    51                     sum[to[i]]+=t[to[i]];
    52                 }
    53                 tim[x]=tim[x]*inv2%mod;
    54                 t[x]=t[x]*inv2%mod;
    55             }
    56         }
    57         for(int x=1;x<=n;++x) if(!vis[x]) for(int i=head[x];i;i=nxt[i]) if(vis[to[i]]&&sz[i]<flag[to[i]]) sum[x]+=t[x]*(flag[to[i]]-sz[i]),sz[i]=flag[to[i]];
    58         ll ans=0; int fl=0;
    59         for(int i=1;i<=n;++i) if(sum[i]){
    60             sum[i]%=mod;
    61             if(tim[i]==1){ fl=1; break; }
    62             ans+=sum[i]*qpow(1-tim[i]+mod,mod-2)%mod;
    63         }
    64         if(fl) puts("-1");
    65         else printf("%lld
    ",ans%mod);
    66     }
    67     return 0;
    68 }
    Yist

    B. Ernd

    因为看到了出现次数,所以想SAM。

    在后面加字符对应着$trans$转移,在前面加字符则对应着向$parent$树上的儿子节点转移。

    每个时刻实际上只关注当前的串与那些串能够匹配,而并不是具体的串的情况。

    所以设$dp_{x,i}$表示SAM上节点$x$,长度为$i$时的最优策略,然而这个状态数为本质不同的字符串个数,随机数据都过不去。

    转移只要讨论三种情况,$trans$转移,$parent$树转移,自转移(保证$i+1<=len_x$)即可。

    因为SAM为一个DAG,实际上要求的是一个拓扑图上的最长链,但是可以在一个点停留多次。

    根据实际含义理解,字符串在长度小的时候的$endpos$集合大小一定大于长度长的时候。

    所以最优策略一定为对于每个节点尽量花完所有的$len$,所以状态数仅为后缀自动机的节点数。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=2e5+7;
     4 int n,root=1,cnt=1,lst=1;
     5 int ch[N<<1][26],prt[N<<1],len[N<<1],f[N<<1];
     6 char s[N];
     7 long long dp[N<<1];
     8 vector<int> ve[N];
     9 inline void extend(int c){
    10     int np=++cnt,p=lst; lst=np;
    11     len[np]=len[p]+1; f[np]=1;
    12     ve[len[np]].push_back(np);
    13     for(;p&&!ch[p][c];p=prt[p]) ch[p][c]=np;
    14     if(!p) prt[np]=root;
    15     else{
    16         int q=ch[p][c];
    17         if(len[q]==len[p]+1) prt[np]=q;
    18         else{
    19             int nq=++cnt; memcpy(ch[nq],ch[q],sizeof(ch[q])); prt[nq]=prt[q];
    20             len[nq]=len[p]+1; ve[len[nq]].push_back(nq); prt[np]=prt[q]=nq;
    21             for(;ch[p][c]==q;p=prt[p]) ch[p][c]=nq;
    22         }
    23     }
    24 }
    25 int main(){
    26     scanf("%d%s",&n,s+1); ve[0].push_back(root);
    27     for(int i=1;i<=n;++i) extend(s[i]-'a');
    28     for(int i=n;i;--i) for(auto x:ve[i]) f[prt[x]]+=f[x];
    29     long long ans=0;
    30     for(int i=0;i<=n;++i) for(auto x:ve[i]){
    31         if(prt[x]) dp[x]=max(dp[x],dp[prt[x]]+1ll*(len[x]-len[prt[x]])*f[x]);
    32         for(int j=0;j<26;++j) if(ch[x][j]) dp[ch[x][j]]=max(dp[ch[x][j]],dp[x]+1ll*(len[ch[x][j]]-len[x])*f[ch[x][j]]);
    33         ans=max(ans,dp[x]);
    34     }
    35     printf("%d
    ",ans);
    36     return 0;
    37 }
    Ernd

    C. Sanrd

    考虑用 拦截导弹 一题的算法,首先预处理出$f$数组,使$f_i$表示强制经过$i$,并且满足LDS长度最大化的LDS方案数。

    所以只要在左右两侧分别求LDS,在$i$处合并就好了。

    现在只要考虑如何求出一个合法的LIS,在删掉这个LIS之后,求一个LDS就好了。

    当一个LIS与所有LDS中的任何一个没有交集,这个LIS就是合法的。

    通过颓题解发现一个性质,LIS与LDS的交集大小不超过1。

    设最大LDS的方案数为$sum$,根据上述性质,LIS的方案$S$是不合法的仅当$sum limits_{i in S}f_i=sum$。

    所以只要求出两个路径上$f$值总和不同的LIS方案,一定有其中一个是合法的,也就可以找到对应的LDS。

    所以问题可以通过一个很恶心(记录最大值/两个转移点/两条路径权值和)的树状数组实现。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int N=5e5+7;
      4 const int mod=998244353;
      5 int n,mxd;
      6 int p[N],Dp[N],dp[N],f[N],F[N],sum[N],Sum[N],vis[N],PRE[N];
      7 pair<int,int> pre[N],Pre[N];
      8 void dfs(int x,int flag){
      9     if(!x) return ;
     10     if(!flag) dfs(pre[x].first,pre[x].second);
     11     else dfs(Pre[x].first,Pre[x].second);
     12     vis[x]=1;
     13 }
     14 void Dfs(int x){
     15     if(!x) return ;
     16     Dfs(PRE[x]);
     17     printf("%d ",x);
     18 }
     19 int mx[N],fa[N];
     20 pair<int,pair<int,int> > pa[N],pb[N];
     21 inline int lowbit(int x){
     22     return x&-x;
     23 }
     24 void modify(int x,int val,int sz){
     25     for(;x<=n+1;x+=lowbit(x))
     26         if(val>mx[x]) mx[x]=val,fa[x]=sz;
     27         else if(val==mx[x]) (fa[x]+=sz)%=mod;
     28 }
     29 inline pair<int,int> query(int x){
     30     pair<int,int> r(0,0);
     31     for(;x;x^=lowbit(x)){
     32         if(mx[x]>r.first) r.first=mx[x],r.second=fa[x];
     33         else if(mx[x]==r.first) (r.second+=fa[x])%=mod;
     34     }
     35     return r;
     36 }
     37 void modify2(int x,int val,int p){
     38     for(;x<=n+1;x+=lowbit(x)) if(val>mx[x]) mx[x]=val,fa[x]=p;
     39 }
     40 inline pair<int,int> query2(int x){
     41     pair<int,int> r(0,0);
     42     for(;x;x^=lowbit(x)) if(mx[x]>r.first) r.first=mx[x],r.second=fa[x];
     43     return r;
     44 }
     45 int main(){
     46     scanf("%d",&n);
     47     for(int i=1;i<=n;++i) scanf("%d",&p[i]);
     48     for(int i=1;i<=n;++i){
     49         dp[i]=1; f[i]=1;
     50         pair<int,int> d=query(n-p[i]+1); ++d.first;
     51         if(d.first>1) dp[i]=d.first,f[i]=d.second;
     52         modify(n-p[i]+1,dp[i],f[i]);
     53         mxd=max(mxd,dp[i]);
     54     }
     55     memset(mx,0,sizeof(mx));
     56     memset(fa,0,sizeof(fa));
     57     for(int i=n;i;--i){
     58         Dp[i]=1; F[i]=1;
     59         pair<int,int> d=query(p[i]); ++d.first;
     60         if(d.first>1) Dp[i]=d.first,F[i]=d.second;
     61         modify(p[i],Dp[i],F[i]);
     62     }
     63     for(int i=1;i<=n;++i){
     64         if(dp[i]+Dp[i]==mxd+1) f[i]=1ll*f[i]*F[i]%mod;
     65         else f[i]=0;
     66     }
     67     p[n+1]=n+1;
     68     memset(mx,-1,sizeof(mx));
     69     memset(fa,0,sizeof(fa));
     70     for(int i=1;i<=n+1;++i){
     71         dp[i]=1; sum[i]=f[i]; Sum[i]=-1;
     72         for(int x=p[i];x;x^=lowbit(x)){
     73             if(mx[x]+1>dp[i]){
     74                 dp[i]=mx[x]+1;
     75                 sum[i]=(pa[x].first+f[i])%mod;
     76                 pre[i]=pa[x].second;
     77                 if(pb[x].first!=-1){
     78                     Sum[i]=(pb[x].first+f[i])%mod;
     79                     Pre[i]=pb[x].second;
     80                 }
     81                 else Sum[i]=-1,Pre[i]=make_pair(0,0);
     82             }
     83             else if(mx[x]+1==dp[i]){
     84                 if((pa[x].first+f[i])%mod!=sum[i]) Sum[i]=(pa[x].first+f[i])%mod,Pre[i]=pa[x].second;
     85                 else if(pb[x].first!=-1&&(pb[x].first+f[i])%mod!=sum[i]) Sum[i]=(pb[x].first+f[i])%mod,Pre[i]=pb[x].second;
     86             }
     87         }
     88         for(int x=p[i];x<=n+1;x+=lowbit(x)){
     89             if(dp[i]>mx[x]){
     90                 mx[x]=dp[i];
     91                 pa[x].first=sum[i];
     92                 pa[x].second=make_pair(i,0);
     93                 pb[x].first=Sum[i];
     94                 pb[x].second=make_pair(i,1);
     95             }
     96             else if(dp[i]==mx[x]){
     97                 if(pa[x].first!=sum[i]){
     98                     pb[x].first=sum[i];
     99                     pb[x].second=make_pair(i,0);
    100                 }
    101                 else if(Sum[i]!=-1&&pa[x].first!=Sum[i]){
    102                     pb[x].first=Sum[i];
    103                     pb[x].second=make_pair(i,1);
    104                 }
    105             }
    106         }
    107     }
    108     dfs(n+1,0);
    109     memset(mx,0,sizeof(mx));
    110     memset(fa,0,sizeof(fa));
    111     int mxv=0,pos=0;
    112     for(int i=1;i<=n;++i) if(!vis[i]){
    113         dp[i]=1;
    114         pair<int,int> d=query2(n-p[i]+1); ++d.first;
    115         if(d.first>1) dp[i]=d.first,PRE[i]=d.second;
    116         modify2(n-p[i]+1,dp[i],i);
    117         if(dp[i]>mxv) mxv=dp[i],pos=i;
    118     }
    119     if(mxv==mxd){
    120         printf("%d
    ",dp[n+1]-1);
    121         for(int i=1;i<=n;++i) if(vis[i]) printf("%d ",i); puts("");
    122         printf("%d
    ",mxv);
    123         Dfs(pos);
    124     }
    125     else{
    126         for(int i=1;i<=n;++i) vis[i]=0;
    127         if(Sum[n+1]==-1) return puts("-1")&0;
    128         dfs(n+1,1); mxv=0; pos=0;
    129         memset(mx,0,sizeof(mx));
    130         memset(fa,0,sizeof(fa));
    131         for(int i=1;i<=n;++i) if(!vis[i]){
    132             dp[i]=1;
    133             pair<int,int> d=query2(n-p[i]+1); ++d.first;
    134             if(d.first>1) dp[i]=d.first,PRE[i]=d.second;
    135             modify2(n-p[i]+1,dp[i],i);
    136             if(dp[i]>mxv) mxv=dp[i],pos=i;
    137         }
    138         if(mxv==mxd){
    139             printf("%d
    ",dp[n+1]-1);
    140             for(int i=1;i<=n;++i) if(vis[i]) printf("%d ",i); puts("");
    141             printf("%d
    ",mxv);
    142             Dfs(pos);
    143         }
    144         else return puts("-1")&0;
    145     }
    146     return 0;
    147 }
    Sanrd
  • 相关阅读:
    vmware安装后设置网络
    博客园添加视频
    博客园音乐插件
    去除数组空格 php
    Jmeter 中多线程并发和循环控制器
    Jmeter对返回体中Json格式的reponse的处理
    Jmeter 抓app包 抓到一半不好用了
    Jmeter ResponseAssertion 【Ignore Status】
    JMeter源码导入到Intellij IDEA
    Jmeter 处理Unicode编码转为中文
  • 原文地址:https://www.cnblogs.com/skyh/p/12188125.html
Copyright © 2011-2022 走看看