[cf1615G]Maximum Adjacent Pairs

考虑所有极长的0,对其长度分类讨论——

1.若其长度为$2m+1$,总是将首/尾与相邻的非0元素配对,其余元素配成$m$对

同时,若首尾中某一个元素对应的$k$已经出现,那么必然与另一个配对

2.若其长度为$2m$,总是配成$m$对或将首/尾均与相邻的非0元素配对,其余元素配成$m-1$对

同时,若首尾中某一个元素对应的$k$已经出现,那么必然直接配成$m$对

 

处理完必然的情况后,不妨仅考虑第1种情况的选择——

将首尾相邻的非0元素连边,即对每一条边选择一个端点并最大化选择的集合

显然每一个连通块是独立的,考虑其中一个连通块:

1.若其为树,任选一点为根并对每一条边选择儿子,即仅有根未被选择

注意到根是任意的,且由于边数$<$点数,因此不可能使所有点均被选择(已经最优)

2.若其不为树,求生成树后额外选一条边即可,即所有节点均被选择

 

进一步的,考虑结合第2种情况(指长度为$2m$)的选择——

同样将首尾相邻的非0元素连边,对于所有选择后者的边,若在同一颗树(指第1种情况中)出现两次显然不优

换言之,将第1种情况中的树上所有点缩点,问题即求此时的最大匹配

这张图中有$o(A)$个点和$o(n)$条边(其中$A=\max_{i=1}^{n}a_{i}$),直接使用带花树算法即可

关于带花树算法,具体即类似匈牙利算法,并当dfs过程中发现奇环时将奇环缩点

通过调整旋转方向,可以使得新图中的增广路也在原图中存在(反之显然),正确性即得证

关于实现方式,略微比较复杂,具体如下——

通常使用bfs代替dfs,并对增广路上(当前)非匹配边中远离起点的点记录另一个点

当发现奇环时,由于之后还需要得到方案,需要将非匹配边的"另一个点"也记录对应的另一个点(即相互记录)

设当前搜到的(非匹配边)为$(x,y)$,将两点交替向上爬(类似求lca),至多多爬一次即可得到该环

另外,对于环上直接通过匹配边拓展的点,其余边也可以拓展,需要重新加入队列

时间复杂度(我觉得)为$o(|V||E|)$,可以通过

时间复杂度为$o(An)$,可以通过

[cf1615G]Maximum Adjacent Pairs
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 300005
  4 #define M 605
  5 #define fi first
  6 #define se second
  7 struct Edge{
  8     int nex,to,tp;
  9 }edge[N<<1];
 10 pair<int,int>v[N];
 11 queue<int>q;
 12 vector<int>bl[M];
 13 int n,m,n0,V,E,x,y,a[N],id[N],visc[N],vis0[N],head[M],vis[M],pos[M],rt[M],fr[M],fa[M],bj[M],pre[M],match[M];
 14 //visc[i]=1当且仅当第i种颜色被使用(1<=i<M-4)
 15 //vis0[i]=1当且仅当第i段已经被完全确定 
 16 void add(int x,int y,int z){
 17     edge[E]=Edge{head[x],y,z};
 18     head[x]=E++;
 19 }
 20 void dfs1(int k,int fa){
 21     if (pos[k]){
 22         rt[V]=k,fr[V]=fa;
 23         return;
 24     }
 25     pos[k]=V;
 26     for(int i=head[k];i!=-1;i=edge[i].nex)
 27         if (edge[i].tp!=fa)dfs1(edge[i].to,edge[i].tp);
 28 }
 29 void dfs2(int k,int fa){
 30     if (vis[k])return;
 31     vis[k]=1;
 32     if (fa){
 33         vis0[fa]=1;
 34         x=v[fa].fi,y=v[fa].se;
 35         if (a[x-1]==k){
 36             a[x]=k;
 37             for(int i=x+1;i<=y;i+=2)a[i]=a[i+1]=id[n0--];
 38         }
 39         else{
 40             a[y]=k;
 41             for(int i=x;i<y;i+=2)a[i]=a[i+1]=id[n0--];
 42         }
 43     }
 44     for(int i=0;i<bl[k].size();i++){
 45         if (vis0[bl[k][i]])continue;
 46         x=v[bl[k][i]].fi,y=v[bl[k][i]].se;
 47         if ((y-x)&1){
 48             vis0[bl[k][i]]=1;
 49             for(int i=x;i<=y;i+=2)a[i]=a[i+1]=id[n0--];
 50         }
 51     }
 52     for(int i=head[k];i!=-1;i=edge[i].nex)
 53         if (edge[i].tp!=fa)dfs2(edge[i].to,edge[i].tp);
 54 }
 55 int find(int k){
 56     if (k==fa[k])return k;
 57     return fa[k]=find(fa[k]);
 58 }
 59 int lca(int x,int y){
 60     bj[0]++,x=find(x),y=find(y);
 61     while (bj[x]!=bj[0]){
 62         bj[x]=bj[0],x=find(pre[match[x]]);
 63         if (y)swap(x,y);
 64     }
 65     return x;
 66 }
 67 void merge(int k,int lst,int x){
 68     while (find(k)!=x){
 69         pre[k]=lst,lst=match[k];
 70         if (find(k)==k)fa[k]=x;
 71         if (find(lst)==lst)fa[lst]=x;
 72         if (vis[lst]>0){
 73             vis[lst]=0;
 74             q.push(lst);
 75         }
 76         k=pre[lst];
 77     }
 78 }
 79 void bfs(int k){
 80     memset(vis,-1,sizeof(vis));
 81     memset(pre,0,sizeof(pre));
 82     for(int i=1;i<=V;i++)fa[i]=i;
 83     while (!q.empty())q.pop();
 84     vis[k]=0,q.push(k);
 85     while (!q.empty()){
 86         int k=q.front();
 87         q.pop();
 88         for(int i=head[k];i!=-1;i=edge[i].nex){
 89             int x=edge[i].to;
 90             if ((find(k)==find(x))||(vis[x]>0))continue;
 91             if (vis[x]<0){
 92                 vis[x]=1,pre[x]=k;
 93                 if (!match[x]){
 94                     while (x){
 95                         int y=pre[x],xx=match[y];
 96                         match[x]=y,match[y]=x,x=xx;
 97                     }
 98                     return;
 99                 }
100                 vis[match[x]]=0,q.push(match[x]);
101                 continue;
102             }
103             int z=lca(k,x);
104             merge(k,x,z),merge(x,k,z); 
105         }
106     }
107 }
108 void calc1(){
109     q.push(0);
110     for(int i=1;i<n;i++)
111         if ((a[i])&&(a[i]==a[i+1]))q.push(a[i]);
112     for(int i=1,j=1;i<=n+1;i++)
113         if ((i>n)||(a[i])){
114             if (j<i){
115                 v[++m]=make_pair(j,i-1);
116                 bl[a[j-1]].push_back(m);
117                 bl[a[i]].push_back(m);
118             }
119             j=i+1;
120         }
121     while (!q.empty()){
122         int k=q.front();
123         q.pop();
124         if (k)visc[k]=1;
125         for(int i=0;i<bl[k].size();i++){
126             if (vis0[bl[k][i]])continue;
127             vis0[bl[k][i]]=1;
128             x=v[bl[k][i]].fi,y=v[bl[k][i]].se;
129             if ((y-x)&1){
130                 for(int i=x;i<=y;i+=2)a[i]=a[i+1]=id[n0--];
131             }
132             else{
133                 if (a[x-1]!=k){
134                     q.push(a[x-1]),a[x]=a[x-1];
135                     for(int i=x+1;i<=y;i+=2)a[i]=a[i+1]=id[n0--];
136                 }
137                 if (a[y+1]!=k){
138                     q.push(a[y+1]),a[y]=a[y+1];
139                     for(int i=x;i<y;i+=2)a[i]=a[i+1]=id[n0--];
140                 }
141                 if ((a[x-1]==k)&&(a[y+1]==k)){
142                     a[y]=1;
143                     for(int i=x;i<y;i+=2)a[i]=a[i+1]=id[n0--];
144                 }
145             }
146         }
147         bl[k].clear();
148     }
149 }
150 void calc2(){
151     E=0;
152     memset(head,-1,sizeof(head));
153     memset(pos,0,sizeof(pos));
154     for(int i=1;i<=m;i++)
155         if (!vis0[i]){
156             x=v[i].fi,y=v[i].se;
157             if ((y-x+1)&1){
158                 add(a[x-1],a[y+1],i);
159                 add(a[y+1],a[x-1],i);
160             }
161         }
162     for(int i=1;i<M-4;i++)
163         if ((!visc[i])&&(!pos[i]))V++,dfs1(i,0);
164     E=0;
165     memset(head,-1,sizeof(head));
166     memset(match,0,sizeof(match));
167     for(int i=1;i<=m;i++)
168         if (!vis0[i]){
169             x=v[i].fi,y=v[i].se;
170             if ((rt[pos[a[x-1]]])||(rt[pos[a[y+1]]]))continue; 
171             if ((y-x)&1){
172                 x=pos[a[x-1]],y=pos[a[y+1]];
173                 if (x!=y)add(x,y,i),add(y,x,i);
174             }
175         }
176     for(int i=1;i<=V;i++)
177         if (!match[i])bfs(i);
178     for(int i=1;i<=V;i++)
179         if ((match[i])&&(i<match[i])){
180             for(int j=head[i];j!=-1;j=edge[j].nex)
181                 if (edge[j].to==match[i]){
182                     vis0[edge[j].tp]=1;
183                     x=v[edge[j].tp].fi,y=v[edge[j].tp].se;
184                     a[x]=rt[pos[a[x-1]]]=a[x-1];
185                     a[y]=rt[pos[a[y+1]]]=a[y+1];
186                     for(int k=x+1;k<y;k+=2)a[k]=a[k+1]=id[n0--];
187                     break;
188                 }
189         }
190     E=0;
191     memset(head,-1,sizeof(head));
192     memset(vis,0,sizeof(vis));
193     for(int i=1;i<=m;i++)
194         if (!vis0[i]){
195             x=v[i].fi,y=v[i].se;
196             if ((y-x+1)&1){
197                 add(a[x-1],a[y+1],i);
198                 add(a[y+1],a[x-1],i);
199             }
200         }
201     for(int i=1;i<M-4;i++)
202         if ((!visc[i])&&(!rt[pos[i]]))rt[pos[i]]=i;
203     for(int i=1;i<=V;i++)dfs2(rt[i],fr[i]);
204     for(int i=1;i<=m;i++)
205         if (!vis0[i]){
206             x=v[i].fi,y=v[i].se;
207             if ((y-x)&1){
208                 for(int j=x;j<=y;j+=2)a[j]=a[j+1]=id[n0--];
209             }
210             else{
211                 a[y]=1;
212                 for(int j=x;j<y;j+=2)a[j]=a[j+1]=id[n0--];
213             }
214         }
215 }
216 int main(){
217     scanf("%d",&n);
218     for(int i=1;i<=n;i++){
219         scanf("%d",&a[i]);
220         visc[a[i]]=1;
221     }
222     for(int i=1;i<=n;i++)
223         if (!visc[i])id[++n0]=i;
224     memset(visc,0,sizeof(visc));
225     calc1(),calc2();
226     for(int i=1;i<=n;i++)printf("%d ",a[i]);
227     return 0;
228 }
View Code

 

上一篇:vue中报错Maximum call stack size exceeded


下一篇:SQLServer实现两个库的字段长度自动更新