题意: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
21n≤k≤32n
询问次数限制大约为:
k
≤
2000
,
Q
≤
4000
k\leq 2000,Q\leq 4000
k≤2000,Q≤4000
orz dmy,dmy是我们的红太阳
转载自dmy的题解
解法:首先,
k
≤
2
k\leq2
k≤2特判
然后,我们将编号位于
(
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∣+2≥k
这时候,考虑环 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
<
k
|path1|+|path2|+2<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((k−4)/2)=k−4
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;
}