[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 }