Submission #1842896


Source Code Expand

#include <bits/stdc++.h>
using namespace std;

#define rep(i,n) for(int (i)=0;(i)<(int)(n);(i)++)
#define rept(i,n) for(int (i)=0;(i)<=(int)(n);(i)++)
#define reps(i,s,n) for(int (i)=(s);(i)<(int)(n);(i)++)
#define repst(i,s,n) for(int (i)=(s);(i)<=(int)(n);(i)++)
#define repr(i,n) for(int (i)=(n);(i)>=0;(i)--)
#define each(itr,v) for(auto (itr):(v))
#define all(c) (c).begin(),(c).end()
#define pb push_back
#define mp(x,y) make_pair((x),(y))
#define fi first
#define se second
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
#define ln "\n"
#define show(x) cout << #x << " = " << x ln
#define dbg(x) cout<<#x"="<<x ln

typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<vector<int> > mat;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const int inf = (int)1e9;
const ll linf = (ll)1e18;
const int mod = (int)(1e9+7);
const int dx[] = {0, 1, 0, -1};
const int dy[] = {1, 0, -1, 0};
const int ddx[] = {0, 1, 1, 1, 0, -1, -1, -1};
const int ddy[] = {1, 1, 0, -1, -1, -1, 0, 1};

struct oreno_initializer {
	oreno_initializer() {
		cin.tie(0);
		ios::sync_with_stdio(0);
	}
} oreno_initializer;

// ━━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…
// .。.:( ^ω^)・゚+.。.:( ^ω^)・゚+.。.:( ^ω^)・゚+.。.:( ^ω^)・゚+.。.:( ^ω^)・゚+
// ・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・‥…━━━☆・

int n, a, b;
vector<vi> e(100000);
ll dpf[100000], dpg[100000], f(int x, int p), g(int x, int p);

// xを親とする部分木に含まれる頂点を、両端が黒にならないように白か黒で塗る組み合わせの数
// pはxの親を表す 親に戻ってループしないように
ll f(int x, int p) {
	if (dpf[x]>0) return dpf[x];
	ll white = g(x,p);
	ll black = 1;
	rep(i,e[x].size()) {
		int to = e[x][i];
		if (to==p) continue;
		black = (black * g(to, x))%mod;
	}
	return dpf[x] = (white + black)%mod;
}

// 頂点pを黒に塗っていてxが白でないといけない場合のxを親とする部分木の塗り方
ll g(int x, int p) {
	if (dpg[x]>0) return dpg[x];
	ll cnt = 1;
	rep(i,e[x].size()) {
		int to = e[x][i];
		if (to==p) continue;
		cnt = (cnt * f(to, x))%mod;
	}
	return dpg[x] = cnt;
}

int main() {
	cin >> n;
	rep(i,n-1) {
		cin >> a >> b;
		a--, b--;
		e[a].pb(b), e[b].pb(a);
	}
	
	/*
	 * treeDPってやつらしい ↓のスライドがすごくわかりやすかった
	 * http://keita-matsushita.hatenablog.com/entry/2016/12/30/180918
	 * まずf(0,-1)が木全体の塗り方の総数(求めたい答え)を表す
	 * 例えば0から頂点1,2,3に辺が伸びているとすると、f(0,-1)は各部分木(0-1-..、0-2-..、0-3-..と続く3つ)の
	 * (0を黒に塗った場合のこの部分木の他の頂点の塗り方の総数) + (0を白に塗った場合の...)
	 * の和で求められる 前者の場合0と隣接している頂点は絶対白で塗る必要があるのでg(to,0)で表せる
	 * 後者だと0と隣接している頂点は白で塗っても黒で塗ってもいいのでf(to,0)
	 * ってことでf(0,-1) = f(1,0)+f(2,0)+f(3,0) + g(1,0)+g(2,0)+g(3,0)となる
	 * これを再帰で繰り返して木全体を探索すればいい
	 */
	
	ll ans = f(0, -1);
	cout << ans << ln;
}

Submission Info

Submission Time
Task D - 塗り絵
User creep04
Language C++14 (GCC 5.4.1)
Score 100
Code Size 3609 Byte
Status AC
Exec Time 43 ms
Memory 7424 KB

Judge Result

Set Name All
Score / Max Score 100 / 100
Status
AC × 22
Set Name Test Cases
All 000.txt, 001.txt, 002.txt, 003.txt, 004.txt, 005.txt, 006.txt, 007.txt, 008.txt, 009.txt, 010.txt, 011.txt, 012.txt, 013.txt, 014.txt, 015.txt, 016.txt, 017.txt, 018.txt, 019.txt, 020.txt, 021.txt
Case Name Status Exec Time Memory
000.txt AC 3 ms 2560 KB
001.txt AC 3 ms 2560 KB
002.txt AC 33 ms 6400 KB
003.txt AC 43 ms 7424 KB
004.txt AC 28 ms 5760 KB
005.txt AC 39 ms 7424 KB
006.txt AC 39 ms 7040 KB
007.txt AC 43 ms 7424 KB
008.txt AC 30 ms 6016 KB
009.txt AC 43 ms 7424 KB
010.txt AC 31 ms 6016 KB
011.txt AC 43 ms 7424 KB
012.txt AC 25 ms 5504 KB
013.txt AC 39 ms 7424 KB
014.txt AC 20 ms 4864 KB
015.txt AC 43 ms 7424 KB
016.txt AC 26 ms 5504 KB
017.txt AC 43 ms 7424 KB
018.txt AC 9 ms 3456 KB
019.txt AC 43 ms 7424 KB
020.txt AC 6 ms 3072 KB
021.txt AC 43 ms 7424 KB