HDU #6664. Andy and Maze 题解--zhengjun

发布时间 2024-01-12 18:08:14作者: A_zjzj

对每个点随机黑白染色,强制答案链的前 \(\lfloor \frac{k}{2}\rfloor\) 个点和后 \(\lceil \frac{k}{2} \rceil\) 个点的颜色不同。

计算答案只需要枚举中间这条两端颜色不同的边 \((u,v,w)\),然后分成两边计算 \(u,v\) 出发的经过 \(1/2/3\) 个点的最长路径,这一部分可以 \(\Theta(n+m)\) 处理出来。

正确率为 \(\frac{1+[2|k]}{2^{k}}\),当 \(k=6\) 时为 \(\frac{1}{32}\)

随机计算 \(B=1000\) 次即可保证正确率,总复杂度 \(\Theta(B\sum (n+m))\)

实测 \(100\) 次就能过……

\(2\le k\le 6\) 时,相比于其余的随机化算法在复杂度和正确率上都有优势。

如果要做 \(k=7,8\),这样的做法需要 \(\Theta(m\sqrt{m})\),加上正确率的降低,可能不会更优秀。

代码

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define all(a) (a).begin(),(a).end()
#ifdef DEBUG
template<class T>
ostream& operator << (ostream &out,vector<T> a){
	out<<'[';
	for(T x:a)out<<x<<',';
	return out<<']';
}
template<class T>
vector<T> ary(T *a,int l,int r){
	return vector<T>{a+l,a+1+r};
}
template<class T>
void debug(T x){
	cerr<<x<<endl;
}
template<class T,class...S>
void debug(T x,S...y){
	cerr<<x<<' ',debug(y...);
}
#else
#define debug(...) void()
#endif
const int N=1e4+10,INF=1e9;
int T,n,m,k,col[N];
mt19937 rnd(time(0));
int ans,fi[N],se[N],d2[N];
vector<pair<int,int>>to[N];
void solve(){
	for(int i=1;i<=n;i++){
		fi[i]=se[i]=d2[i]=-INF;
	}
	auto ins=[&](int u,int w){
		if(w>fi[u])se[u]=fi[u],fi[u]=w;
		else se[u]=max(se[u],w);
	};
	for(int u=1;u<=n;u++){
		for(auto [v,w]:to[u])if(col[u]==col[v])ins(u,w);
	}
	auto calc=[&](int u,int w){
		return fi[u]==w?se[u]:fi[u];
	};
	for(int u=1;u<=n;u++){
		for(auto [v,w]:to[u])if(col[u]==col[v]){
			d2[u]=max(d2[u],w+calc(v,w));
		}
	}
	// debug(ary(col,1,n));
	// debug(ary(fi,1,n));
	// debug(ary(se,1,n));
	// debug(ary(d2,1,n));
	for(int u=1;u<=n;u++)if(col[u]){
		for(auto [v,w]:to[u])if(!col[v]){
			if(k==2)ans=max(ans,w);
			else if(k==3)ans=max(ans,w+max(fi[u],fi[v]));
			else if(k==4)ans=max(ans,w+fi[u]+fi[v]);
			else if(k==5)ans=max({ans,w+d2[u]+fi[v],w+fi[u]+d2[v]});
			else ans=max(ans,w+d2[u]+d2[v]);
		}
	}
}
void get(){
	scanf("%d%d%d",&n,&m,&k);
	for(int u,v,w;m--;){
		scanf("%d%d%d",&u,&v,&w);
		to[u].push_back({v,w}),to[v].push_back({u,w});
	}
	ans=0;
	for(int T=1000;T--;){
		for(int i=1;i<=n;i++)col[i]=rnd()%2;
		solve();
	}
	if(!ans)puts("impossible");
	else printf("%d\n",ans);
}
void clr(){
	for(int i=1;i<=n;i++)to[i].clear();
}
int main(){
	freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	for(scanf("%d",&T);T--;clr())get();
	return 0;
}