[SDOI2012]吊灯(结论)
problem
洛谷鏈接
solution
顯然,顏色相同的燈泡形成一個連通塊,且連通塊的大小 i∣ni\mid ni∣n。
這道題要能發(fā)現(xiàn)一個結(jié)論:一定至少存在一種顏色的連通塊 滿足該聯(lián)通塊內(nèi)的任意一個節(jié)點(diǎn) 都不是異種顏色點(diǎn) 的父親。
即,至少有一個點(diǎn)其子樹(含自己)內(nèi)中所有點(diǎn)顏色均相同。
證明的話,可以考慮將每種顏色連通塊看作一個點(diǎn)。
父親與兒子顏色不同的邊,轉(zhuǎn)化到新圖上的父親顏色連通塊點(diǎn)到兒子顏色聯(lián)通塊點(diǎn)的一條有向邊。
顯然這是一個 DAG\text{DAG}DAG,得證。(如果成環(huán),意味著原圖上某個顏色點(diǎn)就沒有形成一個連通塊而是多個)
拓?fù)渑判騻鬟f連通塊大小,我們可以推出每個連通塊內(nèi)都至少有個點(diǎn) uuu 滿足 i∣sizui\mid siz_ui∣sizu?。
那么就可以做了,本題特殊的性質(zhì)滿足每個點(diǎn)的父親編號都小于自己,直接倒序遍歷統(tǒng)計子樹大小即可。
枚舉聯(lián)通塊大小 iii,枚舉所有 i∣ji\mid ji∣j ,記錄 sizu=jsiz_u=jsizu?=j 的點(diǎn)有 cntjcnt_jcntj? 個,將這些節(jié)點(diǎn)數(shù)累和 tottottot。
最后看 tot?i≥ntot*i\ge ntot?i≥n 是否包含了整棵樹。
code
#include <bits/stdc++.h> using namespace std; #define maxn 1200005 int n; int f[maxn], siz[maxn], cnt[maxn];void read( int &x ) {x = 0; char s = getchar();while( s < '0' or s > '9' ) s = getchar();while( '0' <= s and s <= '9' ) {x = ( x << 1 ) + ( x << 3 ) + ( s ^ 48 );s = getchar();} }int main() {scanf( "%d", &n );for( int i = 2;i <= n;i ++ ) read( f[i] );for( int t = 1;t <= 10;t ++ ) {printf( "Case #%d:\n", t );if( t ^ 1 ) {for( int i = 2;i <= n;i ++ )f[i] = ( f[i] + 19940105 ) % ( i - 1 ) + 1;}for( int i = 1;i <= n;i ++ ) siz[i] = 1, cnt[i] = 0;for( int i = n;i;i -- ) siz[f[i]] += siz[i];//siz[i]:i子樹的大小 含自己for( int i = 1;i <= n;i ++ ) cnt[siz[i]] ++;//cnt[i]:子樹大小為i的節(jié)點(diǎn)個數(shù)for( int i = 1;i <= n;i ++ ) //枚舉連通塊大小if( n % i == 0 ) {int tot = 0;for( int j = 1;j * i <= n;j ++ ) { //加上所有子樹大小為i倍數(shù)的節(jié)點(diǎn)個數(shù)tot += cnt[i * j];if( tot * i >= n ) {//一個節(jié)點(diǎn)至少含i個點(diǎn) 判斷是否包含了整棵樹printf( "%d\n", i );break;}}}}return 0; }總結(jié)
以上是生活随笔為你收集整理的[SDOI2012]吊灯(结论)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全民k歌怎么设置麦克风?全民k歌麦克风设
- 下一篇: 如何使用支付宝充值码