[cf739D]Recover a functional graph

用二元组$A_{i}=(cycle_{i},precycle_{i})$来描述点$i$,则确定$A_{i}$后有解当且仅当:

设$cnt_{(l,h)}$为$A_{i}=(l,h)$的点数量,则$\forall l\ge 1,l\mid cnt_{(l,0)}$且$0\le j\le h,cnt_{(l,j)}\ge 1$(其中$h=\max_{cnt_{(l,j)}\ge 1}j$)

(若不存在$cnt_{(l,j)}\ge 1$则记$h=-1$,正确性和构造方式均显然)

换言之,问题即确定$A_{i}$使得其满足上述条件

记$cnt'_{(l,h)}$为已确定$A_{i}=(l,h)$的点数量,显然最终$cnt_{(l,h)}\ge cnt'_{(l,h)}$,同时其还满足上述条件

简单分析,未确定的$A_{i}$中至少要产生$\lceil\frac{cnt'_{l,0}}{l}\rceil \cdot l-cnt'_{(l,0)}$个$(l,0)$和$\forall 1\le j\le \max_{cnt'_{(l,j)}\ge 1}j,\max(1-cnt'_{(l,j)},0)$个$(l,j)$

另外,若存在$(l,*)$(其中$*$为任意,包括?),则前者的$\lceil\frac{cnt'_{l,0}}{l}\rceil$需要对1取$\max$

仅根据上述条件,可以对未确定的$A_{i}$和需求建立二分图,如果不存在完美匹配(仅考虑需求)即无解

注意到需求数超过$n$显然无解,因此这张二分图的点数和边数分别为$o(n)$和$o(n^{2})$,单次二分图匹配复杂度为$o(n^{3})$

否则,考虑仍未确定的二元组,对其分类讨论:

1.$(?,?)$或$(?,0)$,直接替换为$(1,0)$即可

2.$(l,?)$,根据构造总存在$(l,0)$,因此替换为$(l,1)$即可

3.$(?,h\ge 1)$,显然仅关心于其中最大的$h$,再枚举其所在的$l$即可确定

虽然可能做$n$次二分图匹配,理论复杂度为$o(n^{4})$,但由于常数较小,可以通过

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 305
  4 vector<int>e[N],v[N][N];
  5 vector<pair<int,int> >lim;
  6 int n,m,l[N],h[N],cnt[N][N],mx[N],match[N<<1],vis[N<<1],ans[N];
  7 int read(){
  8     int x=0;
  9     char c=getchar();
 10     while ((c<'0')||(c>'9')){
 11         if (c=='?')return -1;
 12         c=getchar();
 13     }
 14     while ((c>='0')&&(c<='9')){
 15         x=x*10+c-'0';
 16         c=getchar();
 17     }
 18     return x;
 19 }
 20 bool dfs(int k){
 21     if (vis[k])return 0;
 22     vis[k]=1;
 23     for(int i=0;i<e[k].size();i++)
 24         if ((!match[e[k][i]])||(dfs(match[e[k][i]]))){
 25             match[k]=e[k][i],match[e[k][i]]=k;
 26             return 1;
 27         }
 28     return 0;
 29 }
 30 bool calc(){
 31     lim.clear(); 
 32     memset(cnt,0,sizeof(cnt));
 33     memset(mx,-1,sizeof(mx));
 34     memset(vis,0,sizeof(vis));
 35     for(int i=1;i<=n;i++)
 36         if (l[i]>0){
 37             cnt[l[i]][h[i]+1]++;
 38             mx[l[i]]=max(mx[l[i]],h[i]+1);
 39             vis[l[i]]=1;
 40         }
 41     for(int i=1;i<=n;i++){
 42         if (!vis[i])continue;
 43         int s=max((cnt[i][1]+i-1)/i,1)*i-cnt[i][1];
 44         for(int j=0;j<s;j++)lim.push_back(make_pair(i,0));
 45         for(int j=1;j<mx[i];j++)
 46             if (!cnt[i][j+1])lim.push_back(make_pair(i,j));
 47     }
 48     if (lim.size()>n)return 0;
 49     m=lim.size();
 50     for(int i=1;i<=m;i++)e[i].clear();
 51     for(int i=1;i<=n;i++)
 52         if ((l[i]<0)||(h[i]<0)){
 53             for(int j=0;j<lim.size();j++){
 54                 if ((l[i]>0)&&(l[i]!=lim[j].first))continue;
 55                 if ((h[i]>=0)&&(h[i]!=lim[j].second))continue;
 56                 e[j+1].push_back(i+m);
 57             }
 58         }
 59     memset(match,0,sizeof(match));
 60     for(int i=1;i<=m;i++){
 61         memset(vis,0,sizeof(vis));
 62         if (!dfs(i))return 0;
 63     }
 64     for(int i=1;i<=n;i++)
 65         if (match[i+m]){
 66             l[i]=lim[match[i+m]-1].first;
 67             h[i]=lim[match[i+m]-1].second;
 68         }
 69         else{
 70             if ((l[i]<0)&&((h[i]<0)||(!h[i])))l[i]=1,h[i]=0;
 71             if ((l[i]>0)&&(h[i]<0))h[i]=1;
 72             if ((l[i]<0)&&(h[i]>0)){
 73                 for(int j=1;j<=n;j++)
 74                     if (h[i]<mx[j]){
 75                         l[i]=j;
 76                         break;
 77                     }
 78             }
 79         }
 80     for(int i=1;i<=n;i++)
 81         for(int j=0;j<n;j++)v[i][j].clear();
 82     for(int i=1;i<=n;i++)v[l[i]][h[i]].push_back(i);
 83     for(int i=1;i<=n;i++){
 84         for(int j=0;j<v[i][0].size();j++){
 85             if (j%i)ans[v[i][0][j]]=v[i][0][j-1];
 86             else ans[v[i][0][j]]=v[i][0][j+i-1];
 87         }
 88         for(int j=1;j<n;j++)
 89             for(int k=0;k<v[i][j].size();k++)ans[v[i][j][k]]=v[i][j-1][0];
 90     }
 91     for(int i=1;i<n;i++)printf("%d ",ans[i]);
 92     printf("%d\n",ans[n]);
 93     return 1;
 94 }
 95 int main(){
 96     n=read();
 97     int mx=0;
 98     for(int i=1;i<=n;i++){
 99         h[i]=read(),l[i]=read();
100         if (l[i]<0)mx=max(mx,h[i]);
101     }
102     if (!mx){
103         if (!calc())printf("-1\n");
104         return 0;
105     }
106     for(int i=1;i<=n;i++)
107         if ((l[i]<0)&&(h[i]==mx)){
108             bool flag=0;
109             for(l[i]=1;l[i]<=n;l[i]++)
110                 if (calc()){
111                     flag=1;
112                     break;
113                 }
114             if (!flag)printf("-1\n");
115             return 0;
116         }
117     return 0;
118 } 
View Code

 

posted @ 2022-01-08 22:17  PYWBKTDA  阅读(41)  评论(0编辑  收藏  举报