专栏文章

题解:P4796 [BalticOI 2018] 路径

P4796题解参与者 3已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@min910hq
此快照首次捕获于
2025/12/01 22:32
3 个月前
此快照最后确认于
2025/12/01 22:32
3 个月前
查看原文

P4796 [BalticOI 2018] 路径

  • 方法:记忆化搜索。
  • 首先根据题意,可以先打个暴搜,可以得到 7070 分。
暴力搜索CPP
  il void dfs(int u,int fa){
	if(vis[a[u]]) return ;
	vis[a[u]]=1;
	if(fa) ++ans;
	for(int v:g[u]){
		if(v==fa) continue;
		dfs(v,u);
	}
	vis[a[u]]=0;
}
  • 然后考虑优化,注意到一个点可能会遍历多次,并且状态可能一致(即相同颜色集合),考虑用记忆化数组存储,第一维表示点,第二维表示颜色集合,由于 k5k \le 5,可以用状压来表示,转移可以用以下式子表示: fi,S=1+(i,j)E,ajSfj,Sajf_{i,S}=1 + \sum_{(i,j) \in E,a_j \notin S} f_{j,S \cup a_j}
  • 最后答案就是 i=1nfi,ain\sum_{i=1}^n f_{i,a_i}-n,因为路径长 >1>1,所以减去 nn。总复杂度为 O((n+m)×2k)O((n+m) \times 2^k)
codeCPP
#include<bits/stdc++.h>
#define il inline
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
il ll read(){
	ll x=0;bool f=0;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=1;ch=getchar();}
	while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f?-x:x;
}
const int N=3e5+5;
int a[N];
vector<int> g[N];
ll mem[N][1<<5];
int n,m,k;
il void solve();
int main()
{
//	freopen("path.in","r",stdin);
//	freopen("path.out","w",stdout);
	solve();
	return 0;
}
il ll dfs(int u,int fa,int val){
	if((val&(1<<(a[u]-1)))||a[u]>k) return 0;
	int p=val|(1<<(a[u]-1));
	if(mem[u][p]!=-1) return mem[u][p];
	ll res=1;
	for(int v:g[u]){
		if(v==fa) continue;
		res+=dfs(v,u,p);
	}
	return mem[u][p]=res;
}
il void solve(){
	n=read(),m=read(),k=read();
	memset(mem,-1,sizeof(mem));
	for(int i=1;i<=n;++i) a[i]=read();
	for(int i=1,u,v;i<=m;++i)
		u=read(),v=read(),
		g[u].push_back(v),g[v].push_back(u);
	ll ans=0;
	for(int i=1;i<=n;++i) ans+=dfs(i,0,0);
	printf("%lld\n",ans-n);
}
完结撒花。

评论

2 条评论,欢迎与作者交流。

正在加载评论...