kmjp's blog

競技プログラミング参加記です

yukicoder : No.2531 Coloring Vertices on Namori

こちらも割とすんなり。
https://yukicoder.me/problems/no/2531

問題

N点N辺の連結無向グラフが与えられる。
各点をK色のいずれかで塗るとき、辺の両端が同じ色にならないような塗り方は何通りか。

解法

このグラフはいわゆるなもりグラフなので、まず閉路の部分の彩色を考える。
と言ってもこれは典型的なDPで、1頂点選んで色を定めたとき、以後その頂点と同じ色か違う色の場合それぞれを数えて行けばよい。
閉路部分が決まったら、後は閉路から閉路の外側に生えている部分については、閉路内の頂点を根頂点とした根付き木を考えると、親頂点と異なる(K-1)色のいずれかを塗っていけばよいだけ。

int N,K;
set<int> E[202020];

ll dp[202020][2];
const ll mo=998244353;

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>K;
	FOR(i,N) {
		cin>>x>>y;
		x--,y--;
		E[x].insert(y);
		E[y].insert(x);
	}
	queue<int> Q;
	FOR(i,N) if(E[i].size()==1) Q.push(i);
	int num=N;
	while(Q.size()) {
		x=Q.front();
		Q.pop();
		num--;
		FORR(e,E[x]) {
			E[e].erase(x);
			if(E[e].size()==1) Q.push(e);
		}
	}
	
	dp[0][0]=K;
	dp[0][1]=0;
	FOR(i,num-1) {
		dp[i+1][0]=dp[i][1];
		(dp[i+1][1]=dp[i][0]*(K-1)+dp[i][1]*(K-2))%=mo;
	}
	ll ret=dp[num-1][1];
	FOR(i,N-num) ret=ret*(K-1)%mo;
	cout<<ret<<endl;
	
}

まとめ

これも典型かな。