题:https://ac.nowcoder.com/acm/contest/4010/H
题意:找到最大的m,使得存在一个长度为n值域为 [1,m] 的序列,满足任意一组相邻关系都存在。输出为若n>2e6则直接输出m,否则另外输出构造的序列
分析:相邻关系都要有,那么我们可以联想到n^2的大概样子,然后就m个点完全图可以满足含有相邻关系,更有如果考虑最优,那么存在欧拉回路即可满足条件;
因为m对于此题来说具有单调性,所以二分地考虑它,m为奇数时,每个点的度数为偶数,必定存在欧拉回路,,m为偶数时,我们利用让含欧拉回路图的性质俩个节点度数为奇数,其余为偶数,方法就是,俩个奇数度数节点连一条边即可;
最后不足n的部分随便补数即可;
trick:由于欧拉回路是走边的且要回到起点,所以二分时应该对check部分加1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<vector> #include<algorithm> #include<unordered_map> using namespace std; #define pb push_back typedef long long ll; const int inf=0x3f3f3f3f; const int M=2e6+6; struct node{ int v,nextt,w; }e[M<<1]; int head[M],tot; vector<int>ans; void addedge(int u,int v){ e[tot].v=v; e[tot].nextt=head[u]; e[tot].w=0; head[u]=tot++; e[tot].v=u; e[tot].nextt=head[v]; e[tot].w=0; head[v]=tot++; } ll check(int x){ if(x%2) return 1ll*x*(x-1)/2+1;///n是走的边,最后返回要边数加1 else return 1ll*x*(x-1)/2+(x-2)/2+1;///同理加1 } void dfs(int u){ for(int &i=head[u];~i;i=e[i].nextt){ if(e[i].w==1) continue; e[i].w=e[i^1].w=1; dfs(e[i].v); } ans.pb(u); } int main(){ ll n; scanf("%lld",&n); ll l=1,r=2e9; int m; while(l<=r){ int midd=(l+r)>>1; if(check(midd)<=n) m=midd,l=midd+1; else r=midd-1; } if(n>2e6){ return printf("%d ",m),0; } for(int i=0;i<=m;i++) head[i]=-1; for(int i=1;i<=m;i++) for(int j=i+1;j<=m;j++) addedge(i,j); if(m%2==0){ for(int i=3;i<=m;i+=2) addedge(i,i+1); } dfs(1); for(int i=ans.size();i<=n;i++) ans.pb(1); printf("%d ",m); for(int i=0;i<n;i++) if(i!=n-1) printf("%d ",ans[i]); else printf("%d ",ans[i]); return 0; }