考虑除开(1-k)以外的任意点(d)在长度为(k-1)的链上有:
对于任意(i,i+1 (iin [1,k-1])),(col[d][i]+col[d][i+1]<2),否则我们可以直接输出一个红色的(k)条边的链。
30pts
当(2k=n)的时候,我们考虑两个点(p,q)
,如果两者之间是(0)直接连上去,如果是1则我们考虑在(1-k)中选两个点(a,a+1)
,查询(p或q)->(a或a+1)
的颜色。发现我们一定能找到一条p -> (a或a+1) -> q
的路径,否则可以输出红边的答案。
70pts
30pts的问题主要是如果每次第一次查询颜色都是蓝色则会导致长度不够,考虑三个点p,q,r
的时候,我们查寻(6)次,至少有(3)条(0)边,也就是说至少可以让两个点中间插两条边。
这样我们可以变成只剩两条链。用一个端点链接变成一条链
如果是(1/2k)个(>k)的点,现在会剩下3个点,一个是端点,发现正好可以在两边多拓展一个,这样刚好可以凑出来一个(k)条边的。
100pts
把(6)次查询优化成(4)次即可。先查p->a,q->a
,如果同色,则最多再花两次询问找一个。如果不同色,则查询r->a+1
,之后无论如何都只用再查询一次。这样最多查询(4)次
代码
#include <bits/stdc++.h>
#include "graph.h"
using namespace std;
typedef pair<int,int> pii;
map<pair<int,int>, int> table;
inline int qry(int x,int y){
if(x>y)swap(x,y);
if(table.find(pii(x,y))==table.end())
return table[pii(x,y)]=query(x,y);
else return table[pii(x,y)];
}
int KK;
struct link{
int s,t;
vector<int> node;
link(int s=0,int t=0):s(s),t(t){node.push_back(s);}
void rev(){
reverse(node.begin(),node.end());
swap(s,t);
}
inline void add(link y){
t=y.t;
for(size_t i=0;i<y.node.size();i++)node.push_back(y.node[i]);
}
};
vector<link> Lk;
int curpos;
vector<int> Ret;
vector<int> gen(int p,int d){
vector<int> r;
for(int i=0;i<=KK;i++){
if(i>0)r.push_back(i);
if(i==p)r.push_back(d);
}
return r;
}
void push_back(link t){
Lk.push_back(t);
}
bool End;
inline void merge(link a,link b,link c){
link nw;
int d1=qry(a.s,curpos-1);
int d2=qry(b.s,curpos-1);
if(d1==d2&&d2==0){
nw=a;nw.rev();nw.node.push_back(curpos-1);
nw.add(b);
push_back(c);push_back(nw);
return ;
}
else if(d1==d2&&d2==1){
if(qry(a.s,curpos)==1){
Ret=gen(curpos-1,a.s);
End=1;return ;
}if(qry(b.s,curpos)==1){
Ret=gen(curpos-1,b.s);
End=1;return ;
}
nw=a;nw.rev();nw.node.push_back(curpos);
nw.add(b);
push_back(c);push_back(nw);
}
else{
int d3=qry(c.s,curpos);
if(d1==1)
swap(a,b);//d1=0,d2=1
if(!d3){
if(qry(b.s,curpos)==1){
Ret=gen(curpos-1,b.s);
End=1;return ;
}
nw=b;nw.rev();nw.node.push_back(curpos);
nw.add(c);
push_back(a),push_back(nw);
}else{
if(qry(c.s,curpos-1)==1){
Ret=gen(curpos-1,c.s);End=1;
return;
}
nw=a;nw.rev();nw.node.push_back(curpos-1);
nw.add(c);
push_back(b),push_back(nw);
}
}
}
bool sp=0;
vector<int> find_longer_path(int n, int k) {
KK=k;
int n2=(k-1)/2+2;
if(k+n2>n)n2--,sp=1;
for(int j=k+1;j<=k+n2;j++){
Lk.push_back(link(j,j));
}
curpos=3;
while((int)Lk.size()>2){
link a=Lk.back();Lk.pop_back();
link b=Lk.back();Lk.pop_back();
link c=Lk.back();Lk.pop_back();
merge(a,b,c);
if(End)return Ret;
curpos+=2;
}
link a=Lk[0], b=Lk[1];
if(qry(a.s,1))return gen(0,a.s);
if(qry(b.s,1))return gen(0,b.s);
a.rev();a.node.push_back(1);a.add(b);
if((int)a.node.size()>=k+1){
while((int)a.node.size()>k+1)a.node.pop_back();
return a.node;
}else{
if(qry(a.t,k)){
return gen(k,a.t);
}
a.node.push_back(k);a.t=k;
if(a.node.size()<k+1){
a.rev();
int d2=qry(k-1,a.t);
int d3=qry(k-2,a.t);
if(d2&&d3)return gen(k-2,a.t);
else if(!d2){
a.node.push_back(k-1);
}else if(!d3){
a.node.push_back(k-2);
}
}
return a.node;
}
}