zoukankan      html  css  js  c++  java
  • CF1481X Codeforces Round #699

    C Fence Painting(构造)

    有用的刷子贪心刷,没用的刷子填在后续的有用/已存在的位置(用个栈记一下就行)

    D AB Graph(图上构造)

    把边当做三种类型,aa bb ab

    m为奇数时,随便挑一条边来回跑m次就行,一定是回文的

    m为偶数时,如果存在aa or bb边,来回跑m次;如果不存在,那么图中只有ab边。由于这是一张完全图,$nge 3$时一定存在两条连续的首尾相接的ab边,根据m/2的奇偶性即可构造出回文串

    考场后1min敲完,我真行

     1 const int N1=1005; const ll inf=0x3f3f3f3f3f3f3f3fll;
     2 
     3 int n,T,m;
     4 int p[N1][N1];
     5 char str[N1];
     6 int solve()
     7 {
     8     for(int i=1;i<=n;i++) 
     9     {
    10         scanf("%s",str+1);
    11         for(int j=1;j<=n;j++) if(j!=i)
    12             if(str[j]=='a') p[i][j]=0; else p[i][j]=1;
    13     }
    14     int fl;
    15     if(m&1){
    16         puts("YES");
    17         for(int k=0;k<=m;k++) if(k&1) printf("%d ",1); else printf("%d ",2);
    18             puts("");
    19         return 1;
    20     }else{
    21         for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j)
    22         {
    23             if(p[i][j]==p[j][i])
    24             {
    25         puts("YES");
    26                 for(int k=0;k<=m;k++) if(k&1) printf("%d ",i); else printf("%d ",j);
    27             puts("");
    28                 return 1;
    29             }
    30         }
    31         if(n==2) return 0;
    32         for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j)
    33         for(int k=1;k<=n;k++) if(k!=i&&k!=j&&p[i][j]==p[j][k])
    34         {
    35             puts("YES");
    36             if((m/2)&1)
    37             {
    38                 for(int l=0;l<=m/2;l++) if(l&1) printf("%d ",j); else printf("%d ",i);
    39                 for(int l=m/2+1;l<=m;l++) if(l&1) printf("%d ",j); else printf("%d ",k);
    40             }else{
    41                 for(int l=0;l<=m/2;l++) if(l&1) printf("%d ",k); else printf("%d ",j);
    42                 for(int l=m/2+1;l<=m;l++) if(l&1) printf("%d ",i); else printf("%d ",j);
    43             }
    44             puts("");
    45             return 1;
    46         }
    47     }
    48     return 0;
    49 }
    50 
    51 int main()
    52 {
    53     freopen("a.in","r",stdin);
    54     scanf("%d",&T);
    55     while(T--)
    56     {
    57         scanf("%d%d",&n,&m);
    58         int ans=solve();
    59         if(!ans) puts("NO");
    60     }
    61     return 0;
    62 }
    View Code

    E Sorting books(DP)

    题目大意:给你一个序列,每次操作可以把一个数放到最后面,问最少需要多少次操作,能让所有相同的数连在一起。$n=5e5$

    大力$DP$就行

    设$l[i],r[i]$分别表示数i在最左和最右边出现的位置

    设$f[i]$表示$i$到$n$中的所有$l[j]ge i$的数中,可以保留的数字的最大数目,剩下的数都需要按照某种顺序移动到右面

    若$f[i]=l[a_{i}]$,如果把$a[i]$留下,那么在$l[a_{i}]$和$r[a_{i}]$之间的其它数字都不能保留,$f[i]=f[r[a_{i}]+1]+num[a_{i}]$

    如果不保留$a_{i}$,或者$f[i]$不等于$l[a_{i}]$,那么$f[i]=f[i+1]$

    最终答案是$n-f[1]$

    然而会有反例,比如2 2 1 2 2 2 1 1 3,最优方案是挪最左边的1,再把3挪到1的右边,代价为2,上面的DP求出的答案是3,即保留2和3挪1

    这时需要单独考虑挪走尾部一段数的情况

    如果$f[i]$不等于$l[a_{i}]$,例如$f[7]$,保留7和7后面的所有1也是一种可行方案!这其实是在讨论序列最后一个不动的数在哪

     1 const int N1=500005; const int inf=0x3f3f3f3f;
     2 
     3 int n,T,m;
     4 int a[N1],L[N1],R[N1],num[N1],f[N1],id[N1];
     5 // vector<int>pos[N1];
     6 
     7 int main()
     8 {
     9     freopen("a.in","r",stdin);
    10     scanf("%d",&n);
    11     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    12     for(int i=1;i<=n;i++)
    13     {
    14         if(!L[a[i]]) L[a[i]]=R[a[i]]=i;
    15         else{
    16             R[a[i]]=i;
    17         }
    18         num[a[i]]++; id[i]=num[a[i]];
    19         // pos[a[i]].push_back(i);
    20     }
    21     int j;
    22     for(int i=n;i>=1;i--)
    23     {
    24         f[i]=f[i+1]; 
    25         if(i==L[a[i]]){
    26             f[i]=max(f[i],f[R[a[i]]+1]+num[a[i]]);
    27         }else{
    28             f[i]=max(f[i],num[a[i]]-id[i]+1);
    29         }
    30     }
    31     printf("%d
    ",n-f[1]);
    32     return 0;
    33 }
    View Code

    F AB Tree(DP+贪心)

    题目大意:给你一棵树,让你在树的每个节点上填字母,一共要填x个a,n-x个b,问如何填字母,使得根到每个节点的路径组成的串种类最少,$n=1e5$

    设根深度为1,树深度为$D$,可以讨论发现答案不是D就是D+1

    如果答案是$D$,那么所有相同深度的点字母一定相同,x个a能恰好覆盖完一些深度,其它的填b

    考虑用背包$DP$的方法来验证是否存在合法方案,设$f[j]$表示$j$能否被表示

    设$val[i]$表示点的数目,$fre[i]$表示点数为$val[i]$的深度出现的次数

    如果j能被表示,则$f[j-val[i]],f[j-2*val[i]]...f[j-fre[i]*val[i]]$中有一个能被表示

    贪心记录更大的位置,再用滚动数组转移

    不同的点数最多有$O(sqrt n)$种,DP的时间复杂度是$O(nsqrt n)$

    如果答案是$D+1$,必须有一个深度既有a又有b,而且其中的非叶节点必须填相同的字母

    设$num[i],rest[i]$分别表示深度i的节点数和非叶节点数

    现在开始分配a,设还剩p个a

    如果$p>num[i]$,把这个深度填满a

    如果$rest[i]le p<num[i]$,这个位置满足分配条件

    如果$p<rest[i]$,继续看后续有没有满足条件的深度

    可以证明这种方法一定成立,有如下性质

    $rest[i]le num[i+1]$且$rest[i]le num[i]$,$rest[D]=0$

    $rest$最后一定减少到0,容易发现一定存在$rest[i]le p<rest[i-1] le num[i]$

      1 const int N1=100005; const int M1=455; const int inf=0x3f3f3f3f;
      2 
      3 struct EDGE{
      4 int to[N1*2],nxt[N1*2],head[N1],cte;
      5 void ae(int u,int v)
      6 { cte++; to[cte]=v, nxt[cte]=head[u]; head[u]=cte; }
      7 }e;
      8 int n,D,X,Y,type,pre,cur;
      9 int fa[N1],dep[N1],num[N1],rest[N1],col[N1];
     10 vector<int>nodes[N1];
     11 
     12 void dfs(int u)
     13 {
     14     num[dep[u]]++; D=max(D,dep[u]); nodes[dep[u]].push_back(u);
     15     for(int j=e.head[u];j;j=e.nxt[j])
     16     {
     17         int v=e.to[j];
     18         dep[v]=dep[u]+1; dfs(v);
     19     }
     20     if(!e.head[u]) rest[dep[u]]++;
     21 }
     22 int ok[2][N1],id[N1],from[N1],pos[N1];
     23 int freq[N1],val[N1],used[N1],m; 
     24 
     25 void print(int ans)
     26 {
     27     printf("%d
    ",ans);
     28     for(int i=1;i<=n;i++) printf("%c",(col[i]^type)+'a'); 
     29     puts(""); 
     30 }
     31 void findway(int ma)
     32 {
     33     int now=ma,i,j,k,v;
     34     while(now)
     35     {
     36         j=from[now], i=id[now];
     37         used[val[i]]=(now-j)/val[i];
     38         now=j;
     39     }
     40     for(int i=1;i<=D;i++)
     41     {
     42         if(!used[num[i]]) continue;
     43         for(int j=0;j<nodes[i].size();j++)
     44         {
     45             v=nodes[i][j];
     46             col[v]=0;
     47         }
     48         used[num[i]]--;
     49     }
     50 }
     51 int getx(int fl)
     52 {
     53     if(fl)
     54     for(int i=1;i<=D;i++)
     55     {
     56         if(!pos[num[i]]) m++, pos[num[i]]=m, freq[m]=1, val[m]=num[i];
     57         else freq[ pos[num[i]] ]++;
     58     }
     59     memset(ok,0,sizeof(ok));
     60     int now; ok[0][0]=1; pre=0, cur=1;
     61     for(int i=1;i<=m;i++)
     62     {
     63         memcpy(ok[cur],ok[pre],sizeof(ok[cur]));
     64         for(int k=0;k<val[i];k++)
     65         {
     66             now=-1;
     67             for(int j=k;j<=X;j+=val[i])
     68             {
     69                 if(ok[pre][j]) now=j;
     70                 else if(now!=-1&& val[i]*freq[i]>=j-now) 
     71                     ok[cur][j]=1, from[j]=now, id[j]=i;
     72             }
     73         }
     74         swap(cur,pre);
     75         if(ok[pre][X]) break;
     76     }
     77     if(!ok[pre][X]) return 0;
     78     findway(X); print(D);
     79     return 1;
     80 }
     81 int fillma()
     82 {
     83     int x=X;
     84     for(int i=1;i<=D;i++) 
     85     if(x>=rest[i]&&x<=num[i])
     86     {
     87         int re=x-rest[i];
     88         for(int j=0;j<nodes[i].size();j++)
     89         {
     90             int v=nodes[i][j];
     91             if(e.head[v]) col[v]=0;
     92             else if(re) col[v]=0, re--;
     93         }
     94         print(D+1);
     95         return 1;
     96     }else if(x>num[i]){
     97         for(int j=0;j<nodes[i].size();j++)
     98         {
     99             int v=nodes[i][j]; col[v]=0;
    100         }
    101         x-=num[i];
    102     }
    103     return 0;
    104 }
    105 
    106 int main()
    107 {
    108     freopen("a.in","r",stdin);
    109     scanf("%d%d",&n,&X); Y=n-X; if(X>Y) swap(X,Y), type^=1;
    110     for(int i=2;i<=n;i++) scanf("%d",&fa[i]), e.ae(fa[i],i);
    111     dep[1]=1, dfs(1);
    112     for(int i=1;i<=D;i++) rest[i]=num[i]-rest[i];
    113     for(int i=1;i<=n;i++) col[i]=1;
    114     if(getx(1)) return 0;
    115     int ma=0, k;
    116     for(int i=1;i<=D;i++) if(num[i]>ma) ma=num[i], k=i;
    117     fillma();
    118     // if(!) fillend(); 
    119     return 0;
    120 }
    View Code
  • 相关阅读:
    POJ 1330 Nearest Common Ancestors(LCA Tarjan算法)
    LCA 最近公共祖先 (模板)
    线段树,最大值查询位置
    带权并查集
    转负二进制
    UVA 11437 Triangle Fun
    UVA 11488 Hyper Prefix Sets (字典树)
    UVALive 3295 Counting Triangles
    POJ 2752 Seek the Name, Seek the Fame (KMP)
    UVA 11584 Partitioning by Palindromes (字符串区间dp)
  • 原文地址:https://www.cnblogs.com/guapisolo/p/14409282.html
Copyright © 2011-2022 走看看