[uoj 486][神奇交互]在路上了

题意:n个点完全图,每条边颜色为0或1.
已知前k-1个点,到它的下一个编号之间的边都是1.
每次你可以询问一条边的颜色。
已知n,k,找到一条长度为k的简单链。
同时你知道 1 2 n ≤ k ≤ 2 3 n \frac{1}{2}n\leq k \leq \frac{2}{3}n 21nk32n
询问次数限制大约为:
k ≤ 2000 , Q ≤ 4000 k\leq 2000,Q\leq 4000 k2000,Q4000


orz dmy,dmy是我们的红太阳
转载自dmy的题解


解法:首先, k ≤ 2 k\leq2 k2特判
然后,我们将编号位于 ( 1 , k ) (1,k) (1,k)的点称为蓝点,编号位于 ( k , n ] (k,n] (k,n]的称为红点
一条全蓝路径定义为首尾均为蓝点,路径上全为蓝边,且红蓝交错的路径
我们动态维护两条全蓝路径path1,path2
同时,为了更好地分析操作次数,我们分类,分别为a,b,c
1) ∣ p a t h 1 ∣ + ∣ p a t h 2 ∣ + 2 ≥ k |path1|+|path2|+2\geq k path1+path2+2k
这时候,考虑 1-path1-k-path2
若其中有红边,该条红边的端点肯定含1或k,那么很容易构造出一条红链
这种操作次数加到a去
排除了这种情况,我们进行分类讨论
1’ ∣ p a t h 1 ∣ + ∣ p a t h 2 ∣ + 2 > k |path1|+|path2|+2> k path1+path2+2>k
路径1-path1-k-path2即为所求
2’ ∣ p a t h 1 ∣ + ∣ p a t h 2 ∣ + 2 = k |path1|+|path2|+2=k path1+path2+2=k
这个时候,一定还有两个相邻的红点未被选取,称为i,i+1
记r为path1的第一个节点,为蓝点
询问r连上i,i+1的颜色
均为红,构造出 1... , i , r , i + 1 , . . . , k 1...,i,r,i+1,...,k 1...,i,r,i+1,...,k
否则有蓝,则可以构造出该点-path1-k-path2-1
这里询问两次,加到b上
2) ∣ p a t h 1 ∣ + ∣ p a t h 2 ∣ + 2 &lt; k |path1|+|path2|+2&lt;k path1+path2+2<k
考虑扩展path1和path2的长度总和
容易知道,一定存在蓝点r,红点i,i+1未被选取
取path1的一个端节点x,path2的一个端节点y
连接x-i,y-i
这里操作两次,加到c上
均为红,检查x-i+1,y-i+1,这里两次,加到a上
有红,容易构造红链
为蓝,通过i+1将path1和path2连接起来
让path2变为r
均为蓝, 通过i将path1和path2连接起来,让path2变成r
有红有蓝,设x红y蓝(对i而言)
检查r~i+1的连边,为红,检查r-i,为红,构造红链,为蓝,构造y-i-r,形成新的path2,以上两次操作加到a上
为蓝,检查x-i+1,为红,构造红链,为蓝,构造x-i+1-r,形成新的path2,以上两次操作加到a上
不断执行,大于等于K时执行(1)的操作即可

下面是喜闻乐见的分析操作次数的地方
b,最多为2
c, 2 ( ( k − 4 ) / 2 ) = k − 4 2((k-4)/2)=k-4 2((k4)/2)=k4
a,注意到,将第一种情况(不包括第二种情况)中检测r~i+1的操作想成y-i
采取势能分析的办法,每次检测相当于检测一条边加进这个环中是不是蓝边
最多加k+1边
当然,如果你愿意,可以将第一部分的优化到三次(不算b的次数),即只查询链
但是博主懒,于是博主要2k-1次
未来图灵奖的获得者dmy只要2k-2次
被打爆了!被打爆了!被打爆了!

#include <bits/stdc++.h>
using namespace std;
#include"graph.h" 

int n,K;
#define Maxn 4005
int rel[Maxn][Maxn];
int path1[Maxn],l1=0,path2[Maxn],l2=0;
void Query(int a,int b){
	if(rel[a][b]!=-1)return;
	rel[a][b]=rel[b][a]=query(a,b);
}
bool vis[Maxn];
int seq[Maxn];
vector<int> Ans;
bool Flag=false;
void dfs(int u,int col,int ed){
	if(Flag)return;
	seq[ed+1]=u;
	vis[u]=true;
	if(ed==K){
		Flag=true;
		for(int i=1;i<=K+1;++i)Ans.push_back(seq[i]);
		return;
	}
	for(int i=1;i<=n;++i)
	    if(!vis[i]&&rel[u][i]==col)
	    	dfs(i,col,ed+1);
	vis[u]=false;
}

void orz_dmy3(int x){
	Ans.push_back(x);
	for(int i=1;i<=K;++i)Ans.push_back(i);
}
void orz_dmy4(int x){
	for(int i=1;i<=K;++i)Ans.push_back(i);
	Ans.push_back(x);
}
void orz_dmy5(int x,int id){
	for(int i=1;i<=id;++i)Ans.push_back(i);
	Ans.push_back(x);
	for(int i=id+1;i<=K;++i)Ans.push_back(i);
} 

void orz_dmy1(){
	int id,r;
	for(int i=2;i<K-1;++i)
	    if(!vis[i]&&!vis[i+1]){
		    id=i;
		    break;
		}
	for(int i=K+1;i<=n;++i)
	    if(!vis[i])r=i;
	
	int x=path1[l1],y=path2[1];
	Query(x,id);Query(y,id);
	if(rel[x][id]&&rel[y][id]){
		Query(x,id+1);if(rel[x][id+1]){orz_dmy5(x,id);Flag=true;return;}
		Query(y,id+1);if(rel[y][id+1]){orz_dmy5(y,id);Flag=true;return;}
		path1[++l1]=id+1;
		for(int i=1;i<=l2;++i)path1[++l1]=path2[i];
		path2[l2=1]=r;
		vis[id+1]=vis[r]=true;
	}else if(rel[x][id]==0&&rel[y][id]==0){
		path1[++l1]=id;
		for(int i=1;i<=l2;++i)path1[++l1]=path2[i];
	    path2[l2=1]=r;
	    vis[id]=vis[r]=true;
	}else{
		if(!rel[x][id]){
			for(int i=1;i<=max(l1,l2);++i)swap(path1[i],path2[i]);
			swap(l1,l2);
			reverse(path1+1,path1+l1+1);
			reverse(path2+1,path2+l2+1);
			x=path1[l1];
			y=path2[1]; 
		}
		Query(id+1,r);
		if(rel[id+1][r]){
			Query(r,id);
			if(rel[r][id]){orz_dmy5(r,id);Flag=true;return;}
			reverse(path2+1,path2+l2+1);
			path2[++l2]=id;
			path2[++l2]=r;
			vis[r]=vis[id]=true;
		}else{
			Query(x,id+1);
			if(rel[x][id+1]){orz_dmy5(x,id);Flag=true;return;}
			path1[++l1]=id+1;
			path1[++l1]=r;
			vis[id+1]=vis[r]=true;
		}
	}
}

void orz_dmy2(){
	int id;
	for(int i=2;i<K-1;++i)
	    if(!vis[i]&&!vis[i+1]){
	    	id=i;
	    	break;
		}
	int r=path1[1];
	Query(r,id);Query(r,id+1);
	if(rel[r][id]&&rel[r][id+1])orz_dmy5(r,id);
	else{
		if(!rel[r][id]){
			Ans.push_back(id);
			for(int i=1;i<=l1;++i)Ans.push_back(path1[i]);
			Ans.push_back(K);
			for(int i=1;i<=l2;++i)Ans.push_back(path2[i]);
			Ans.push_back(1);
		}else{
			Ans.push_back(id+1);
			for(int i=1;i<=l1;++i)Ans.push_back(path1[i]);
			Ans.push_back(K);
			for(int i=1;i<=l2;++i)Ans.push_back(path2[i]);
			Ans.push_back(1);
		}
	}
}


vector<int> find_longer_path(int n_,int k_){
	n=n_;K=k_;//dmy 吼强啊
	memset(rel,-1,sizeof(rel));
	for(register int i=1;i<K;++i)rel[i][i+1]=1;//dmy 是我们的红太阳  
	if(K<=5){
		for(int i=1;i<=n;++i)
		    for(int j=i+1;j<=n;++j)Query(i,j);
		for(register int i=1;i<=n;++i)
	        dfs(i,1,0);		
	    for(register int i=1;i<=n;++i)
	       dfs(i,0,0);
	    return Ans;
	}
	path1[++l1]=K+1;path2[++l2]=K+2;vis[K+1]=vis[K+2]=true;
	while(l1+l2+2<K){
		orz_dmy1();
		if(Flag)return Ans;
	}
	Query(1,path1[1]);
	if(rel[1][path1[1]]==1){
	    orz_dmy3(path1[1]);
		return Ans;
	}
	Query(path1[l1],K);
	if(rel[path1[l1]][K]==1){
	    orz_dmy4(path1[l1]);
		return Ans;
	}
	Query(K,path2[1]);
	if(rel[K][path2[1]]==1){
	    orz_dmy4(path2[1]);
		return Ans;
	}
	Query(path2[l2],1);
	if(rel[path2[l2]][1]==1){
	    orz_dmy3(path2[l2]);
		return Ans;
    } 
	if(l1+l2+2==K){
	    orz_dmy2();
		return Ans;
	}	
	else{
		Ans.push_back(1);
		for(int i=1;i<=l1;++i)Ans.push_back(path1[i]);
		Ans.push_back(K);
		for(int i=1;i<=l2;++i)Ans.push_back(path2[i]);
	}
	return Ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值