• SHOI2015零件组装机


    乱搞构造




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

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

    如何找到这个点呢?

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

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

    时间复杂度(O(nlog_n))

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    const int N=1e5+4;
    vector<int>e[N];
    set<int>st[N];
    int gcd(int x,int y){
    	return y==0?x:gcd(y,x%y);
    }
    bool solve(int l,int r){
    	if(l==r)return 1;
    	if(l>r||e[l].empty())return 0;
    	int d=e[l][e[l].size()-1]-l,id=-1,cnt=0;
    	for(int i=e[l].size()-1,u;i>=0;i--){
    		u=e[l][i];cnt++;
    		if(gcd(u-l,d)==u-l&&(r-l)/(u-l)==cnt&&r-u+1>=u-l){id=u;break;}
    	}
    	if(id==-1)return 0;
    	for(int i=l,u;i<id;i++){
    		u=(r-i)/(id-l);
    		while(u){
    			if(e[i][e[i].size()-1]!=i+(id-l)*u)return 0;
    			u--;
    			e[i].pop_back();
    		}
    	}
    	return solve(l,id-1)&&solve(id,r);
    }
    int main(){
    	int T=read(),n,m,fl;
    	while(T--){
    		n=read();m=read();
    		fl=0;
    		for(int i=0;i<n;i++){e[i].clear();st[i].clear();}
    		for(int i=1,u,v;i<=m;i++){
    			u=read();v=read();
    			if(u==v)fl=1;
    			if(u>v)u^=v^=u^=v;
    			if(!st[u].count(v)){st[u].insert(v);e[u].push_back(v);}
    			else fl=1;
    		}
    		if(fl){puts("NO");continue;}
    		for(int i=0;i<n;i++)sort(e[i].begin(),e[i].end());
    		if(solve(0,n-1))puts("YES");
    		else puts("NO");
    	} 
    	return (0-0);
    }
    

    mine:

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

    注意判重边自环

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    const int N=1e5+4;
    int n,m,vis[N];
    vector<int>e[N];
    bool solve(int l,int r){
    	if(l>=r)return 1;
    	int duan=-1;
    	for(int i=r,pre,u,mx;i>=l;i--){
    		if(e[i].empty()){duan=i;break;}
    		u=e[i][e[i].size()-1];
    		vis[u]=1;
    		if(i==r)mx=u;
    		if(i==r||u==pre-1){pre=u;continue;}
    		if(pre==l&&u>=mx){duan=u;break;}
    		if(vis[u]){duan=i;break;}
    		return 0;
    	}
    	if(duan==-1||duan-l+1>r-duan)return 0;
    	for(int i=l;i<=r;i++)vis[i]=0;
    	for(int i=duan+1,len=duan-l+1;i<=r;i++){
    		if(e[i].empty()||(e[i][e[i].size()-1]!=(i-duan-1)%len+l))return 0;
    		e[i].pop_back();
    	}
    	return solve(l,duan)&&solve(duan+1,r);
    }
    #define ll long long
    inline void work(){
    	n=read();m=read();
    	for(int i=1;i<=n;i++)e[i].clear();
    	int fl=0;
    	map<ll,bool>mp;
    	ll x;
    	for(int i=1,u,v;i<=m;i++){
    		u=read();v=read();
    		if(u==v)fl=1;
    		if(u>v)u^=v^=u^=v;
    		x=(ll)u*N+v;
    		if(mp[x])fl=1;
    		mp[x]=1;
    		e[v].push_back(u);
    	}
    	if(fl){puts("NO");return;}
    	for(int i=0;i<n;i++)sort(e[i].begin(),e[i].end(),greater<int>());
    	puts(solve(0,n-1)?"YES":"NO");
    }
    int main(){
    	int T=read();
    	while(T--)work();	
    	return (0-0);
    }
    
  • 相关阅读:
    SDOI 2016 数字配对
    SDOI 2016 征途 决策单调性
    SDOI 2016 生成魔咒
    SDOI 2016 排列计数
    【SC主题公园杯】三个袋子 = =不动脑的后果
    【BZOJ3050】【USACO 2013 Jan Gold金组】坐座位 Seating
    MillerRabin 快速的素数概率判定法
    [POJ3189][cqbzoj1640]稳定的奶牛分配 解题报告
    最大流 isap 模板
    【POJ 1324】Holedox Moving A*宽搜
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12566743.html
Copyright © 2020-2023  润新知