乱搞构造




想到判断是否可行,可以找一个分割点,判断能否在此分割,递归左右两边

但是!!只有一个分割点可行(抽象理解一下,后面的向前面的点循环连边,若移动分割点会打坏循环)

如何找到这个点呢?

方法很多,仔细想想都可以想到,这里提供一种思路

遍历第一个点(即0号点)的连边情况,找到一个分割点使得其余边与此点形成倍数关系,剩下的点刚好形成剩下的边数个循环,当然还有前半部分要小于后半部分(具体看代码理解一下就好)

时间复杂度\(O(nlog_n)\)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. inline int read(){
  4. int x=0,f=1;char c=getchar();
  5. while(!isdigit(c)){if(c==\'-\')f=-1;c=getchar();}
  6. while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
  7. return f==1?x:-x;
  8. }
  9. const int N=1e5+4;
  10. vector<int>e[N];
  11. set<int>st[N];
  12. int gcd(int x,int y){
  13. return y==0?x:gcd(y,x%y);
  14. }
  15. bool solve(int l,int r){
  16. if(l==r)return 1;
  17. if(l>r||e[l].empty())return 0;
  18. int d=e[l][e[l].size()-1]-l,id=-1,cnt=0;
  19. for(int i=e[l].size()-1,u;i>=0;i--){
  20. u=e[l][i];cnt++;
  21. if(gcd(u-l,d)==u-l&&(r-l)/(u-l)==cnt&&r-u+1>=u-l){id=u;break;}
  22. }
  23. if(id==-1)return 0;
  24. for(int i=l,u;i<id;i++){
  25. u=(r-i)/(id-l);
  26. while(u){
  27. if(e[i][e[i].size()-1]!=i+(id-l)*u)return 0;
  28. u--;
  29. e[i].pop_back();
  30. }
  31. }
  32. return solve(l,id-1)&&solve(id,r);
  33. }
  34. int main(){
  35. int T=read(),n,m,fl;
  36. while(T--){
  37. n=read();m=read();
  38. fl=0;
  39. for(int i=0;i<n;i++){e[i].clear();st[i].clear();}
  40. for(int i=1,u,v;i<=m;i++){
  41. u=read();v=read();
  42. if(u==v)fl=1;
  43. if(u>v)u^=v^=u^=v;
  44. if(!st[u].count(v)){st[u].insert(v);e[u].push_back(v);}
  45. else fl=1;
  46. }
  47. if(fl){puts("NO");continue;}
  48. for(int i=0;i<n;i++)sort(e[i].begin(),e[i].end());
  49. if(solve(0,n-1))puts("YES");
  50. else puts("NO");
  51. }
  52. return (0-0);
  53. }

mine:

从后面开始,找到一个循环即可得知断开的长度,不符合的情况根据不同的样例判一下就好

注意判重边自环

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. inline int read(){
  4. int x=0,f=1;char c=getchar();
  5. while(!isdigit(c)){if(c==\'-\')f=-1;c=getchar();}
  6. while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
  7. return f==1?x:-x;
  8. }
  9. const int N=1e5+4;
  10. int n,m,vis[N];
  11. vector<int>e[N];
  12. bool solve(int l,int r){
  13. if(l>=r)return 1;
  14. int duan=-1;
  15. for(int i=r,pre,u,mx;i>=l;i--){
  16. if(e[i].empty()){duan=i;break;}
  17. u=e[i][e[i].size()-1];
  18. vis[u]=1;
  19. if(i==r)mx=u;
  20. if(i==r||u==pre-1){pre=u;continue;}
  21. if(pre==l&&u>=mx){duan=u;break;}
  22. if(vis[u]){duan=i;break;}
  23. return 0;
  24. }
  25. if(duan==-1||duan-l+1>r-duan)return 0;
  26. for(int i=l;i<=r;i++)vis[i]=0;
  27. for(int i=duan+1,len=duan-l+1;i<=r;i++){
  28. if(e[i].empty()||(e[i][e[i].size()-1]!=(i-duan-1)%len+l))return 0;
  29. e[i].pop_back();
  30. }
  31. return solve(l,duan)&&solve(duan+1,r);
  32. }
  33. #define ll long long
  34. inline void work(){
  35. n=read();m=read();
  36. for(int i=1;i<=n;i++)e[i].clear();
  37. int fl=0;
  38. map<ll,bool>mp;
  39. ll x;
  40. for(int i=1,u,v;i<=m;i++){
  41. u=read();v=read();
  42. if(u==v)fl=1;
  43. if(u>v)u^=v^=u^=v;
  44. x=(ll)u*N+v;
  45. if(mp[x])fl=1;
  46. mp[x]=1;
  47. e[v].push_back(u);
  48. }
  49. if(fl){puts("NO");return;}
  50. for(int i=0;i<n;i++)sort(e[i].begin(),e[i].end(),greater<int>());
  51. puts(solve(0,n-1)?"YES":"NO");
  52. }
  53. int main(){
  54. int T=read();
  55. while(T--)work();
  56. return (0-0);
  57. }

版权声明:本文为aurora2004原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/aurora2004/p/12566743.html