20190129模拟题

  • 题解:

    • 一个子序列的匹配最优的情况一定可以尽量靠前;
    • 预处理每个位置的下一个0和1的位置;
    • f[i][j]表示在和A串和B串匹配到的位置,枚举下一个0/1转移;
    • 出现非子序列的状态是f[n+1][m+1];
    • 倒着转移,正着输出答案;
  •  1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=4010;
     4 int n,m,nt1[N][2],nt2[N][2],f[N][N];
     5 char s[N];
     6 int main(){
     7     freopen("sequence.in","r",stdin);
     8     freopen("sequence.out","w",stdout);
     9     scanf("%s",s+1);
    10     n = strlen(s+1);
    11     nt1[n+1][0]=nt1[n+1][1]=n+1;
    12     for(int i=n;~i;--i)
    13     for(int j=0;j<2;++j){
    14         nt1[i][j] = s[i+1]==48+j?i+1:nt1[i+1][j];
    15     }
    16     scanf("%s",s+1);
    17     m=strlen(s+1);
    18     nt2[m+1][0]=nt2[m+1][1]=m+1;
    19     for(int i=m;~i;--i)
    20     for(int j=0;j<2;++j){
    21         nt2[i][j] = s[i+1]==48+j?i+1:nt2[i+1][j];
    22     }
    23     memset(f,0x3f,sizeof(f));
    24     f[n+1][m+1]=0;
    25     for(int i=n+1;~i;--i)
    26     for(int j=m+1;~j;--j)
    27     for(int k=0;k<2;++k){
    28         f[i][j] = min(f[i][j],f[nt1[i][k]][nt2[j][k]]+1);
    29     }
    30     for(int i=0,j=0;i!=n+1||j!=m+1;){
    31         if(f[i][j]==f[nt1[i][0]][nt2[j][0]]+1){
    32             i=nt1[i][0],j=nt2[j][0];
    33             putchar('0');
    34         }else{
    35             i=nt1[i][1],j=nt2[j][1];
    36             putchar('1');
    37         }
    38     }
    39     return 0;
    40 }
    sequence

  • 题解:

    • 从小到大依次考虑每一个相同的值,可以发现不同的值相互独立,并且当前最小值一定移动到左右两边;
    • 依次考虑每个不同的$a[i]$的答案,对于这个值的一个位置来说,比它小的已经移动都到了左右两边;
    • 所以当前位置移动到左右两边的代价分别是原来位置左右两边比它大的个数;
    • 这时可以贪心枚举断点,分别计算左右两边的贡献,对所有断点取最小值即可;
  •  1 #include<bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 const int N=100010;
     5 int n,c[N],a[N],l[N],r[N];
     6 ll pre[N],suf[N];
     7 ll ans;
     8 vector<int>g[N];
     9 void add(int x){for(;x<=1e5;x+=x&-x)c[x]++;}
    10 int que(int x){int re=0;for(;x;x-=x&-x)re+=c[x];return re;}
    11 ll solve(int x){
    12     int m=g[x].size();
    13     pre[0]=l[g[x][0]];suf[m]=0;
    14     for(int i=1;i<m;++i)pre[i]=pre[i-1]+l[g[x][i]];
    15     for(int i=m-1;~i;--i)suf[i]=suf[i+1]+r[g[x][i]]; 
    16     ll re=suf[0];
    17     for(int i=0;i<m;++i)re=min(re,pre[i]+suf[i+1]);
    18     return re;
    19 }
    20 int main(){
    21     freopen("card.in","r",stdin);
    22     freopen("card.out","w",stdout);
    23     scanf("%d",&n);
    24     for(int i=1;i<=n;++i)scanf("%d",&a[i]),g[a[i]].push_back(i);
    25     for(int i=1;i<=n;++i)l[i]=i-1-que(a[i]),add(a[i]);
    26     memset(c,0,sizeof(c));
    27     for(int i=n;i;--i)r[i]=n-i-que(a[i]),add(a[i]);
    28     for(int i=1;i<=n;++i)if(g[a[i]].size())ans+=solve(a[i]),g[a[i]].clear();
    29     cout<<ans<<endl;
    30     return 0;
    31 }
    card

 

  • 题解

    • 同bzoj3991
    • 需要对每个颜色维护一下虚树的大小;
    • 考虑$n$个点的虚树,按$dfs$序走一圈就是树边*2;
    • $set$维护一下$dfs$序即可;
  •  1 #include<bits/stdc++.h>
     2 #define mk make_pair
     3 #define fir first
     4 #define sec second
     5 using namespace std;
     6 const int N=100010;
     7 int n,m,st[N],idx,o=1,hd[N],col[N],ans[N],fa[N][20],dep[N],bin[20],cnt[N];
     8 char ch[10];
     9 typedef pair<int,int>pii;
    10 set<pii>s[N];
    11 set<pii>::iterator it1,it2,it;
    12 struct Edge{int v,nt;}E[N<<1];
    13 void adde(int u,int v){
    14     E[o]=(Edge){v,hd[u]};hd[u]=o++;
    15     E[o]=(Edge){u,hd[v]};hd[v]=o++;
    16 }
    17 int lca(int u,int v){
    18     if(dep[u]<dep[v])swap(u,v);
    19     for(int i=0;i<=18;++i)if((dep[u]-dep[v])&bin[i])u=fa[u][i];
    20     if(u==v)return u;
    21     for(int i=18;~i;--i)if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
    22     return fa[u][0]; 
    23 }
    24 int dis(int u,int v){
    25     return dep[u]+dep[v]-2*dep[lca(u,v)];
    26 }
    27 void ins(int x,int u){
    28     s[x].insert(mk(st[u],u));
    29     it1 = it2 = s[x].lower_bound(mk(st[u],u));
    30     if(it1==s[x].begin())it1=s[x].end();
    31     --it1;it2++;
    32     if(it2==s[x].end())it2=s[x].begin();
    33     int u1 = (*it1).sec , u2 = (*it2).sec;
    34     ans[x] -= dis(u1,u2) ; 
    35     ans[x] += dis(u1,u) + dis(u2,u);
    36 }
    37 void del(int x,int u){
    38     it = it1 = it2 = s[x].lower_bound(mk(st[u],u));
    39     if(it1==s[x].begin())it1=s[x].end();
    40     --it1;it2++;
    41     if(it2==s[x].end())it2=s[x].begin();
    42     int u1 = (*it1).sec , u2 = (*it2).sec;
    43     ans[x] -= dis(u1,u) + dis(u2,u);
    44     ans[x] += dis(u1,u2) ; 
    45     s[x].erase(it);
    46 }
    47 void dfs(int u,int F){
    48     st[u]=++idx;
    49     for(int i=1;bin[i]<=dep[u];++i)fa[u][i]=fa[fa[u][i-1]][i-1];
    50     ins(col[u],u);
    51     for(int i=hd[u];i;i=E[i].nt){
    52         int v=E[i].v;
    53         if(v==F)continue;
    54         dep[v]=dep[u]+1;
    55         fa[v][0]=u;
    56         dfs(v,u);
    57     }
    58 }
    59 int main(){
    60     freopen("tree.in","r",stdin);
    61     freopen("tree.out","w",stdout);
    62     for(int i=bin[0]=1;i<=18;++i)bin[i]=bin[i-1]<<1;
    63     scanf("%d",&n);
    64     for(int i=1,u,v;i<n;++i){
    65         scanf("%d%d",&u,&v);
    66         adde(u,v);
    67     }
    68     for(int i=1;i<=n;++i)scanf("%d",&col[i]),cnt[col[i]]++;
    69     dfs(1,0);
    70     scanf("%d",&m);
    71     for(int i=1,u,x,y;i<=m;++i){
    72         scanf("%s",ch);
    73         if(ch[0]=='U'){
    74             scanf("%d%d",&u,&x);
    75             cnt[x]++;
    76             cnt[col[u]]--;
    77             del(col[u],u);
    78             ins(col[u]=x,u);
    79         }else {
    80             scanf("%d",&x);
    81             if(!cnt[x])puts("-1");
    82             else printf("%d\n",ans[x]>>1); 
    83         }
    84     }
    85     return 0;
    86 }
    tree

     

 

posted @ 2019-01-29 18:33  大米饼  阅读(207)  评论(0编辑  收藏  举报