• 2017-2018 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)


    A. Odd Palindrome

    所有回文子串长度都是奇数等价于不存在长度为$2$的偶回文子串,即相邻两个字符都不同。

    #include<cstdio>
    #include<cstring>
    char a[1111111];int n,i;
    int main(){
    	scanf("%s",a+1);
    	n=strlen(a+1);
    	for(i=1;i<n;i++)if(a[i]==a[i+1])return puts("Or not."),0;
    	puts("Odd.");
    }
    

      

    B. Enlarging Enthusiasm

    注意到方案数不超过$(n-1) imes (n-1)!$,爆搜出所有可行方案即可,需要大量常数优化。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=15;
    int n,m,i,a[N],f[(1<<12)+5],ans;
    int cnt[(1<<12)+5];
    int w[N];
    void dfs(int S,int mx,int q,int x){
    	if(!S){
    		ans++;
    		return;
    	}
    	mx++;
    	if((S&-S)==S){
    		int j=f[S];
    		int nowq=mx-j>q?mx-j:q;
    		if(x>=nowq)ans++;
    		return;
    	}
    	int U=S;
    	while(U){
    		int i=U&-U,j=f[i];
    		int nowq=mx-j>q?mx-j:q;
    		if(x>=nowq)dfs(S^i,j+nowq,nowq,x-nowq);
    		U^=i;
    	}
    }
    void gao(int S,int mx,int q,int x){
    	if(!S){
    		ans++;
    		return;
    	}
    	mx++;
    	for(int U=S;U;U-=U&-U){
    		int i=U&-U;
    		if(i==(1<<(n-1)))continue;
    		int nowq=mx-f[i];
    		if(nowq<q)nowq=q;
    		if(x>=nowq)dfs(S^i,f[i]+nowq,nowq,x-nowq);
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	
    	for(i=1;i<1<<n;i++)cnt[i]=cnt[i>>1]+(i&1);
    	for(w[0]=i=1;i<=n;i++)w[i]=w[i-1]*i;
    	
    	for(i=0;i<n;i++)scanf("%d",&a[i]);
    	sort(a,a+n);
    	for(i=0;i<n;i++)f[1<<i]=a[i];
    	gao((1<<n)-1,a[n-1],0,m);
    	printf("%d",ans);
    }
    /*
    12 700
    1 2 3 4 5 6 7 8 9 10 11 12
    */
    

      

    C. Fear Factoring

    考虑每个约数的贡献,那么分段等差数列求和即可。

    时间复杂度$O(sqrt{b})$。

    #include<cstdio>
    typedef long long ll;
    ll cal(ll n){
    	ll i,j;
    	ll ans=0;
    	for(i=1;i<=n;i=j+1){
    		j=n/(n/i);
    		ans+=(i+j)*(j-i+1)*(n/i);
    	}
    	return ans;
    }
    int main(){
    	ll a,b;
    	scanf("%lld%lld",&a,&b);
    	printf("%lld",(cal(b)-cal(a-1))/2);
    }
    

      

    D. Rainbow Roads

    对于每个点,若其有超过一条同色的边,那么对应子树都不是Good点,差分前缀和打标记即可。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef pair<int,int>P;
    const int N=300010;
    int n,i,j,k,x,y,z,g[N],v[N],w[N],nxt[N],ed;
    int f[N],dfn,st[N],en[N];
    int m,ans,s[N];
    P q[N];
    inline void add(int x,int y,int z){
    	v[++ed]=y;
    	w[ed]=z;
    	nxt[ed]=g[x];
    	g[x]=ed;
    }
    void dfs(int x,int y){
    	st[x]=++dfn;
    	f[x]=y;
    	for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x);
    	en[x]=dfn;
    }
    int main(){
    	scanf("%d",&n);
    	for(i=1;i<n;i++){
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z),add(y,x,z);
    	}
    	dfs(1,0);
    	for(i=1;i<=n;i++){
    		m=0;
    		for(j=g[i];j;j=nxt[j])q[++m]=P(w[j],v[j]);
    		sort(q+1,q+m+1);
    		for(j=1;j<=m;j=k){
    			for(k=j;k<=m&&q[j].first==q[k].first;k++);
    			if(k>j+1){
    				for(x=j;x<k;x++){
    					y=q[x].second;
    					if(y==f[i]){
    						s[1]++;
    						s[st[i]]--;
    						s[en[i]+1]++;
    					}else{
    						s[st[y]]++;
    						s[en[y]+1]--;
    					}
    				}
    			}
    		}
    	}
    	for(i=1;i<=n;i++)s[i]+=s[i-1];
    	for(i=1;i<=n;i++)if(!s[st[i]])ans++;
    	printf("%d
    ",ans);
    	for(i=1;i<=n;i++)if(!s[st[i]])printf("%d
    ",i);
    }
    

      

    E. Straight Shot

    二分水平分速度,检查最终是否走到了$(x,0)$。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N=111;
    int n,i;
    double X,V,dx,dy;
    double lim,goal=1e100,tmp,L,R,MID,l[N],r[N],v[N];
    double cal(double dy){
    	double dx=sqrt(V*V-dy*dy);
    	double x=0,y=0;
    	for(int i=1;i<=n;i++){
    		y+=dy*(l[i]-x);
    		y+=(dy+v[i])*(r[i]-l[i]);
    		x=r[i];
    	}
    	y+=dy*(X-x);
    	tmp=X/dx;
    	return y/dx;
    }
    int main(){
    	scanf("%d%lf%lf",&n,&X,&V);
    	for(i=1;i<=n;i++)scanf("%lf%lf%lf",&l[i],&r[i],&v[i]);
    	L=-V,R=V;
    	for(int _=1000;_;_--){
    		MID=(L+R)/2;
    		if(cal(MID)<0)L=MID;else R=MID;
    	}
    	lim=X/V*2;
    	L=(L+R)/2;
    	if(fabs(cal(L))<1e-8){
    		cal(L);
    		goal=tmp;
    	}
    	if(goal>lim+1e-8)puts("Too hard");
    	else printf("%.3f",goal);
    }
    

      

    F. Distinct Distances

    答案点只可能取在每个点、两个点的中点,以及两对点垂直平分线的交点。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N=50;
    const double eps=1e-9;
    inline int sgn(double x){
    	if(x>eps)return 1;
    	if(x<-eps)return -1;
    	return 0;
    }
    struct P{
    	double x,y;
    	P(){}
    	P(double _x,double _y){x=_x,y=_y;}
    	P operator+(P b){return P(x+b.x,y+b.y);}
    	P operator-(P b){return P(x-b.x,y-b.y);}
    	P operator*(double b){return P(x*b,y*b);}
    	P operator/(double b){return P(x/b,y/b);}
    	void read(){scanf("%lf%lf",&x,&y);}
    	double len(){return x*x+y*y;}
    	double dis(const P&b){return (x-b.x)*(x-b.x)+(y-b.y)*(y-b.y);}
    	bool operator==(P b){return !sgn(x-b.x)&&!sgn(y-b.y);}
    	P rot90(){return P(-y,x);}
    }a[N],e[N*N][2];
    int n,m,i,j,ans=N;
    double d[N];
    inline void solve(P O){
    	//printf("%.10f %.10f
    ",O.x,O.y);
    	int i;
    	for(i=1;i<=n;i++)d[i]=O.dis(a[i]);
    	sort(d+1,d+n+1);
    	int t=1;
    	for(i=2;i<=n&&t<ans;i++)if(d[i]>d[i-1]+eps)t++;
    	if(t<ans)ans=t;
    }
    inline void makeline(P a,P b){
    	if(a==b)return;
    	P c=(a+b)/2.0;
    	solve(c);
    	b=b-a;
    	e[++m][0]=c;
    	e[m][1]=c+b.rot90();
    	//printf("%.5f %.5f %.5f %.5f
    ",e[m][0].x,e[m][0].y,e[m][1].x,e[m][1].y);
    }
    inline double cross(P a,P b){
    	return a.x*b.y-a.y*b.x;
    }
    inline void gao(P a,P b,P p,P q){
    	double U=cross(p-a,q-p),D=cross(b-a,q-p);
    	if(!sgn(D))return;
    	//puts("!");
    	solve(a+(b-a)*(U/D));
    }
    int main(){
    	scanf("%d",&n);
    	for(i=1;i<=n;i++)a[i].read();
    	for(i=1;i<=n;i++)solve(a[i]);
    	for(i=1;i<=n;i++)for(j=1;j<i;j++){
    		makeline(a[i],a[j]);
    	}
    	//makeline(a[4],a[5]);
    	//makeline(a[5],a[1]);
    	for(i=1;i<=m;i++)for(j=1;j<i;j++)gao(e[i][0],e[i][1],e[j][0],e[j][1]);
    	printf("%d",ans);
    }
    /*
    6
    0 -5
    1 0
    -1 0
    2 3
    3 2
    -3 0
    */
    

      

    G. Security Badge

    对区间离散化,那么只需要检查$O(m)$个人是否可行,每次暴力Floodfill判断即可。

    时间复杂度$O(m(n+m))$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=10010;
    int n,m,k,S,T,i,j,cnt,q[N],K;
    int g[N],ed,v[N],vc[N],vd[N],nxt[N],vis[N],ans;
    inline void add(int x,int y,int c,int d){
    	v[++ed]=y;
    	vc[ed]=c;
    	vd[ed]=d;
    	nxt[ed]=g[x];
    	g[x]=ed;
    }
    void dfs(int x){
    	if(vis[x])return;
    	vis[x]=1;
    	for(int i=g[x];i;i=nxt[i])if(vc[i]<=K&&K<=vd[i])dfs(v[i]);
    }
    int main(){
    	scanf("%d%d%d%d%d",&n,&m,&k,&S,&T);
    	for(i=1;i<=m;i++){
    		int a,b,c,d;
    		scanf("%d%d%d%d",&a,&b,&c,&d);
    		add(a,b,c,d);
    		q[++cnt]=c-1;
    		q[++cnt]=d;
    	}
    	sort(q+1,q+cnt+1);
    	for(i=2;i<=cnt;i++)if(q[i]!=q[i-1]){
    		K=q[i];
    		for(j=1;j<=n;j++)vis[j]=0;
    		dfs(S);
    		if(vis[T])ans+=q[i]-q[i-1];
    	}
    	printf("%d",ans);
    }
    

      

    H. Avoiding Airports

    将每架飞机拆成上飞机和下飞机两个事件,并按照时间顺序依次考虑。

    设$dp[x]$表示最后乘坐第$x$架飞机的最小代价,那么转移是经典斜率优化形式,对于每个点用单调队列维护凸壳即可。

    时间复杂度$O(mlog m)$。

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int N=200010;
    const ll inf=1LL<<60;
    int n,m,i,e[N][4],cnt;
    struct E{
    	int x,y;
    	E(){}
    	E(int _x,int _y){x=_x,y=_y;}
    }w[N<<1];
    ll dp[N],ans=inf;
    struct Line{
    	ll k,b;
    	Line(){}
    	Line(ll _k,ll _b){k=_k,b=_b;}
    	ll f(ll x){return k*x+b;}
    };
    vector<Line>g[N];
    int head[N],tail[N],deg[N];
    inline bool cmp(const E&a,const E&b){
    	if(a.x!=b.x)return a.x<b.x;
    	return a.y<b.y;
    }
    inline double pos(const Line&a,const Line&b){
    	return 1.0*(a.b-b.b)/(b.k-a.k);
    }
    inline void ins(int o,ll k,ll b){
    	if(b>=inf)return;
    	Line now(k,b);
    	int&h=head[o],&t=tail[o];
    	if(h<=t){
    		if(g[o][t].k==k){
    			if(g[o][t].b<=b)return;
    			t--;
    		}
    	}
    	while(h<t&&pos(g[o][t-1],g[o][t])>=pos(g[o][t],now))t--;
    	g[o][++t]=now;
    }
    inline ll cal(int o,ll x){
    	int&h=head[o],&t=tail[o];
    	if(h>t)return inf;
    	while(h<t&&g[o][h].f(x)>g[o][h+1].f(x))h++;
    	return g[o][h].f(x);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(i=1;i<=m;i++){
    		scanf("%d%d%d%d",&e[i][0],&e[i][1],&e[i][2],&e[i][3]);
    		deg[e[i][1]]++;
    		w[++cnt]=E(e[i][2],-i);//s
    		w[++cnt]=E(e[i][3],i);//e
    	}
    	sort(w+1,w+cnt+1,cmp);
    	deg[1]++;
    	for(i=1;i<=n;i++)tail[i]=-1,g[i].resize(deg[i]+2);
    	ins(1,0,0);//kx+b
    	for(i=1;i<=cnt;i++){
    		int x=w[i].y;
    		//printf("->%d %d
    ",w[i].x,x);
    		if(x<0){
    			int y=-x;
    			dp[y]=cal(e[y][0],e[y][2]);
    			if(dp[y]<inf)dp[y]+=1LL*e[y][2]*e[y][2];
    			//printf("! %d %lld
    ",y,dp[y]);
    		}else{
    			//printf("ins %d %lld
    ",e[x][1],dp[x]);
    			ins(e[x][1],-2LL*e[x][3],dp[x]+1LL*e[x][3]*e[x][3]);
    		}
    	}
    	for(i=1;i<=m;i++)if(e[i][1]==n)ans=min(ans,dp[i]);
    	printf("%lld",ans);
    }
    /*
    3 5
    1 1 10 20
    1 2 30 40
    1 2 50 60
    1 2 70 80
    2 3 90 95
    
    
    5 8
    1 2 1 10
    2 4 11 16
    2 1 9 12
    3 5 28 100
    1 2 3 8
    4 3 20 21
    1 3 13 27
    3 5 23 24
    */
    

      

    I. Long Long Strings

    初始串取字符集无穷的超长字符串是最坏情况,压缩区间后暴力操作即可。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 0, M = 0, Z = 1e9 + 7;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    const LL inf = 1e12;
    struct A
    {
    	LL st;
    	LL ed;
    	LL stval;
    	bool operator < (const A &b)const
    	{
    		return st < b.st;
    	}
    };
    set<A>sot1, sot2;
    void doit(set<A> &sot)
    {
    	char ch;
    	while(~scanf(" %c", &ch))
    	{
    		if(ch == 'D')
    		{
    			LL pos;
    			scanf("%lld", &pos);
    			auto it = --sot.upper_bound({pos});
    			LL st = it->st;
    			LL ed = it->ed;
    			LL stval = it->stval;
    			sot.erase(it);
    			vector<A>vt;
    			if(st <= pos - 1)
    			{
    				vt.push_back({st, pos - 1, stval});
    			}
    			if(pos + 1 <= ed)
    			{
    				vt.push_back({pos, ed - 1, stval + pos + 1 - st});
    			}
    			for(auto w=sot.lower_bound({pos + 1}),nxt = w;w!= sot.end();w=nxt)
    			{
    				nxt = w; ++nxt;
    				vt.push_back({w->st - 1, w->ed - 1, w->stval});
    				sot.erase(w);
    			}
    			for(auto it : vt)sot.insert(it);
    		}
    		else if(ch == 'I')
    		{
    			char val_;
    			LL pos, val;
    			scanf("%lld %c", &pos, &val_);
    			val = inf + val_;
    			auto it = --sot.upper_bound({pos});
    			LL st = it->st;
    			LL ed = it->ed;
    			LL stval = it->stval;
    			sot.erase(it);
    			vector<A>vt;
    			if(st <= pos - 1)
    			{
    				vt.push_back({st, pos - 1, stval});
    			}
    			if(pos <= ed)
    			{
    				vt.push_back({pos + 1, ed + 1, stval + pos - st});
    			}
    			for(auto w=sot.lower_bound({pos + 1}),nxt = w;w!= sot.end();w=nxt)
    			{
    				nxt = w; ++nxt;
    				vt.push_back({w->st + 1, w->ed + 1, w->stval});
    				sot.erase(w);
    			}
    			vt.push_back({pos, pos, val});
    			for(auto it : vt)sot.insert(it);
    		}
    		else break;
    		/*
    		for(auto it : sot)
    		{
    			printf("%lld %lld %lld
    ", it.st, it.ed, it.stval);
    		}
    		puts("show end");
    		*/
    	}	
    }
    bool check()
    {
    	LL ed1 = (--sot1.end())->ed;
    	LL ed2 = (--sot1.end())->ed;
    	if(ed1 != ed2)return 0;
    	LL now = 1;
    	while(now <= ed1)
    	{
    		auto it1 = sot1.begin();
    		auto it2 = sot2.begin();
    		LL ed1 = it1->ed;
    		LL ed2 = it2->ed;
    		if(it1->stval != it2->stval)return 0;
    		LL stval = it1->stval;
    		LL nxt = min(it1->ed, it2->ed) + 1;
    		sot1.erase(it1);
    		sot2.erase(it2);
    		if(nxt <= ed1)
    		{
    			sot1.insert({nxt, ed1, nxt - now + stval});
    		}
    		if(nxt <= ed2)
    		{
    			sot2.insert({nxt, ed2, nxt - now + stval});
    		}
    		now = nxt;
    	}
    	return 1;
    }
    int main()
    {
    	sot1.clear();
    	sot1.insert({1, inf, 1});
    	sot2.clear();
    	sot2.insert({1, inf, 1});
    	doit(sot1);
    	doit(sot2);
    	/*
    	for(auto it : sot1)
    	{
    		printf("%lld %lld %lld
    ", it.st, it.ed, it.stval);
    	}
    	puts("-------------");
    	for(auto it : sot2)
    	{
    		printf("%lld %lld %lld
    ", it.st, it.ed, it.stval);
    	}
    	*/
    	puts(check() ? "0" : "1");
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    J. Grid Coloring

    设$f[i][j]$表示考虑前$i$行,第$i$行前$j$个都是蓝色,后面都是红色的方案数,暴力转移即可。

    时间复杂度$O(n^3)$。

    #include<cstdio>
    typedef long long ll;
    const int N=40;
    int n,m,i,j,k;
    ll ans,f[N][N];
    char a[N][N];
    bool can[N][N];
    inline bool check(int x,int y){
    	for(int i=1;i<=y;i++)if(a[x][i]=='R')return 0;
    	for(int i=y+1;i<=m;i++)if(a[x][i]=='B')return 0;
    	return 1;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(i=1;i<=n;i++)scanf("%s",a[i]+1);
    	for(i=1;i<=n;i++){
    		for(j=0;j<=m;j++){
    			can[i][j]=check(i,j);
    		}
    	}
    	//f[i][j] [1..j] is B, j+1..m is R
    	for(j=0;j<=m;j++)f[1][j]=can[1][j];
    	for(i=1;i<n;i++)for(j=0;j<=m;j++)for(k=0;k<=j;k++)f[i+1][k]+=f[i][j]*can[i+1][k];
    	for(j=0;j<=m;j++)ans+=f[n][j];
    	printf("%lld",ans);
    }
    

      

    K. Spinning Up Palindromes

    显然最优解中一定是从右往左操作,故问题可以转化成:给定数字$A$,找到一个数位和最小的数字$B$,使得$A+B$是回文串。

    考虑从两边往中间DP,设$f[i][j][k]$表示考虑前后$i$个位置,前面希望后面进位为$j$,后面对前面进位为$k$的最小代价。

    #include<cstdio>
    #include<cstring>
    const int N=50,inf=10000000;
    int n,m,l,r,i,j,k,x,y,t,w;
    char s[N];
    int a[N],f[N][2][2],ans=inf;
    inline void up(int&a,int b){a>b?(a=b):0;}
    int main(){
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	for(i=1;i<=n;i++)a[i]=s[i]-'0';
    	for(i=0;i<=n+5;i++)for(j=0;j<2;j++)for(k=0;k<2;k++)f[i][j][k]=inf;
    	f[0][0][0]=f[0][1][0]=0;
    	for(l=1,r=n;l<r;l++,r--)for(i=0;i<2;i++)for(j=0;j<2;j++)if(f[l-1][i][j]<inf){
    		w=f[l-1][i][j];
    		for(x=0;x<10;x++)for(y=0;y<10;y++){//what is b
    			for(k=0;k<2;k++){//jinwei from l+1
    				int A=a[l]+x+k,nA=0;
    				if(A>=10)A-=10,nA++;
    				if(nA!=i)continue;
    				int B=a[r]+y+j,nB=0;
    				if(B>=10)B-=10,nB++;
    				if(A!=B)continue;
    				up(f[l][k][nB],w+x+y);
    			}
    		}
    	}
    	m=n/2;
    	if(n%2){
    		for(i=0;i<2;i++)for(j=0;j<2;j++)if(f[m][i][j]<inf){
    			w=f[m][i][j];
    			for(x=0;x<10;x++){
    				if((a[m+1]+x+j)/10!=i)continue;
    				up(ans,w+x);
    			}
    		}
    	}else{
    		for(i=0;i<2;i++)for(j=0;j<2;j++)if(f[m][i][j]<inf){
    			w=f[m][i][j];
    			if(i==j)up(ans,w);
    		}
    	}
    	printf("%d",ans);
    }
    

      

    L. Delayed Work

    暴力枚举人数即可。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    ll K,P,X,i;double ans;
    int main(){
    	scanf("%lld%lld%lld",&K,&P,&X);
    	ans=1e20;
    	for(i=1;i<=3000000;i++){
    		ans=min(ans,1.0*K*P/i+1.0*X*i);
    	}
    	printf("%.3f",ans);
    }
    

      

    M. Unsatisfying

    若初始2-SAT无解,那么答案显然为$0$。

    如果不存在$ eg xlor eg y$,那么无解。

    否则枚举每个$x$,强行规定$x=true$,若2-SAT无解则答案为$1$。

    否则答案只能为$2$。

    时间复杂度$O(n(n+m))$。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 4010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    
    
    int n, m, nn;
    int x, y;
    vector<int> a[N];
    bool pick[N];
    int sta[N], top;
    bool dfs(int x)
    {
    	if(pick[x ^ 1]) return 0;
    	if(pick[x]) return 1;
    	pick[x] = 1;
    	sta[++ top] = x;
    	for(int i = a[x].size() - 1; ~ i; -- i){
    		int y = a[x][i];
    		if(!dfs(y)) return 0;
    	}
    	return 1;
    }
    bool solve()
    {
    	for(int i = 0; i < nn; i += 2) if(!pick[i] && !pick[i ^ 1]){
    		top = 0;
    		if(!dfs(i)){
    			while(top) pick[sta[top --]] = 0;
    			top = 0;
    			if(!dfs(i ^ 1)) return 0;
    		}
    	}
    	return 1;
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	int flag = 0;
    	nn = n * 2;
    	for(int i = 0; i < nn; i ++) pick[i] = 0, a[i].clear();
    	for(int i = 1; i <= m; i ++){
    		scanf("%d%d", &x, &y);
    		int xx = abs(x), yy = abs(y);
    		xx *= 2; yy *= 2;
    		xx --; yy --;
    		if(x < 0 && y < 0) flag = 1;
    		if(x < 0 && y < 0){
    			a[xx].push_back(yy ^ 1);
    			a[yy].push_back(xx ^ 1);
    			//printf("%d %d
    ", xx, yy ^ 1);
    			//printf("%d %d
    ", yy, xx ^ 1);
    			
    		}
    		else if(x < 0 && y > 0){
    			a[xx].push_back(yy);
    			a[yy ^ 1].push_back(xx ^ 1);
    			//printf("%d %d
    ", xx, yy);
    			//printf("%d %d
    ", yy ^ 1, xx ^ 1);
    			
    		}
    		else if(x > 0 && y < 0){
    			a[yy].push_back(xx);
    			a[xx ^ 1].push_back(yy ^ 1);
    			//printf("%d %d
    ", yy, xx);
    			//printf("%d %d
    ", xx ^ 1, yy ^ 1);
    			
    		}
    		else if(x > 0 && y > 0){
    			a[xx ^ 1].push_back(yy);
    			a[yy ^ 1].push_back(xx);
    			//printf("%d %d
    ", xx ^ 1, yy);
    			//printf("%d %d
    ", yy ^ 1, xx);
    			
    		}
    	}
    	if(!flag){puts("-1"); return 0;}
    	if(!solve()) {puts("0"); return 0;}
    	for(int i = 1; i <= n; i ++){
    		for(int j = 0; j < nn; j ++){
    			//a[i].clear();
    			pick[j] = 0;
    		}
    		int xx = i * 2 - 1;	
    		//a[xx].push_back(xx ^ 1);
    		a[xx ^ 1].push_back(xx);
    		
    		if(!solve()){
    			puts("1"); return 0;
    		}
    		//a[xx].pop_back();
    		a[xx ^ 1].pop_back();
    	}
    	puts("2");
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    4 5
    1 2
    0 3
    2 1
    -1 -3
    1 4
    5 0
    -2 3
    3 5
    4 2
    3 -4
    7 5
    4 6
    -2 -3
    3 4
    5 2
    0
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

  • 相关阅读:
    数据结构:练习题
    Node.js尝鲜——留言功能
    html+JavaBean+jsp实现用户注册
    我的安全之路——Web安全篇
    Java模拟储蓄卡和信用卡
    AngularJS尝鲜——联动菜单
    AngularJS尝鲜——Ajax请求
    AngularJS尝鲜——增减商品购买量
    Knight Tournament (set)
    Anniversary party (树形DP)
  • 原文地址:https://www.cnblogs.com/clrs97/p/7841819.html
Copyright © 2020-2023  润新知