1. 程式人生 > >洛谷 P3237 [HNOI2014]米特運輸 解題報告

洛谷 P3237 [HNOI2014]米特運輸 解題報告

use 6.2 單向 新建 方法 輸入數據 最大 根節點 不能

P3237 [HNOI2014]米特運輸

題目描述

米特是\(D\)星球上一種非常神秘的物質,蘊含著巨大的能量。在以米特為主要能源的D星上,這種米特能源的運輸和儲存一直是一個大問題。

\(D\)星上有\(N\)個城市,我們將其順序編號為1到\(N\),1號城市為首都。這\(N\)個城市由\(N-1\)條單向高速通道連接起來,構成一棵以1號城市(首部)為根的樹,高速通道的方向由樹中的兒子指向父親。樹按深度分層:根結點深度為0,屬於第1層;根結點的子節點深度為1,屬於第2層;依此類推,深度為i的結點屬於第\(i+1\)層。

建好高速通道之後,\(D\)星人開始考慮如何具體地儲存和傳輸米特資源。由於發展程度不同,每個城市儲存米特的能力不盡相同,其中第\(i\)

個城市建有一個容量為\(A[i]\)的米特儲存器。這個米特儲存器除了具有儲存的功能,還具有自動收集米特的能力。

如果到了晚上六點,有某個儲存器處於未滿的狀態,它就會自動收集大氣中蘊含的米特能源,在早上六點之前就能收集滿;但是,只有在儲存器完全空的狀態下啟動自動收集程序才是安全的,未滿而又非空時啟動可能有安全隱患。

早上六點到七點間,根節點城市(1號城市)會將其儲存器裏的米特消耗殆盡。根節點不會自動搜集米特,它只接受子節點傳輸來的米特。

早上七點,城市之間啟動米特傳輸過程,傳輸過程逐層遞進:先是第2層節點城市向第1層(根節點城市,即1號城市)傳輸,直到第1層的儲存器滿或第2層的儲存器全為空;然後是第3層向第2層傳輸,直到對於第2層的每個節點,其儲存器滿或其子節點(位於第3層)的儲存器全為空;依此類推,直到最後一層傳輸完成。傳輸過程一定會在晚上六點前完成。

由於技術原因,運輸方案需要滿足以下條件:

(1)不能讓某個儲存器到了晚上六點傳輸結束時還處於非空但又未滿的狀態,這個時候儲存器仍然會啟動自動收集米特的程序,而給已經儲存有米特的儲存器啟動收集程序可能導致危險,也就是說要讓儲存器到了晚上六點時要麽空要麽滿;

(2)關於首都——即1號城市的特殊情況, 每天早上六點到七點間1號城市中的米特儲存器裏的米特會自動被消耗殆盡,即運輸方案不需要考慮首都的米特怎麽運走;

(3)除了1號城市,每個節點必須在其子節點城市向它運輸米特之前將這座城市的米特儲存器中原本存有的米特全部運出去給父節點,不允許儲存器中殘存的米特與外來的米特發生混合;

(4)運向某一個城市的若幹個來源的米特數量必須完全相同,不然,這些來源不同的米特按不同比例混合之後可能發生危險。

現在D星人已經建立好高速通道,每個城市也有了一定儲存容量的米特儲存器。為了滿足上面的限制條件,可能需要重建一些城市中的米特儲存器。你可以,也只能,將某一座城市(包括首都)中原來存在的米特儲存器摧毀,再新建一座任意容量的新的米特儲存器,其容量可以是小數(在輸入數據中,儲存器原始容量是正整數,但重建後可以是小數),不能是負數或零,使得需要被重建的米特儲存器的數目盡量少。

輸入輸出格式

輸入格式:

第一行是一個正整數\(N\),表示城市的數目。 接下來\(N\)行,每行一個正整數,其中的第\(i\)行表示第\(i\)個城市原來存在的米特儲存器的容量。 再接下來是\(N-1\)行,每行兩個正整數\(a\)\(b\)表示城市\(b\)到城市\(a\)有一條高速通道\((a≠b)\)

輸出格式:

輸出文件僅包含一行,一個整數,表示最少的被重建(即修改儲存器容量)的米特儲存器的數目。


這是個語文題!!!

經過漫長的,令人乏味的讀題以後,終於化簡了這個模型。

對於這棵樹t的每個節點i:
1.父節點的兒子的值之和等於父節點的值。
2.父節點的所有兒子之值都相等。

從樸素出發。枚舉每個點的值不變動,然後處理其他點。找到處理的最小值。復雜度:\(O(n^2)\)

思考一下,我們每次枚舉一個點,對樹中任意一點\(k\),它一定會達到某個值\(w\)

如果某個值\(w\)出現的次數最多,那麽我們把這個點換成這值就是最優的。

我也不知道這算啥,我把它描述為“到達某目標狀態的可轉移方案數的最大值”

類似的思想有\(NOIP2005\)的“篝火晚會”,那題比這個題要簡單。

我們以根節點為基準點(因為這樣不會出現小數)

枚舉每一個點的值不換時根節點的狀態,找到轉移次數最多的一個狀態的次數,用總點數減去即為答案。

我們可以預先處理出根節點應該是每個點權值的多少倍。

但是這樣會爆\(long long\)
有三個解決方法:
1.高精。可能會爆
2.\(hash\)。我處理長整形自動溢出取膜居然\(wa\)了一半,結果換成長者生日秒過,太厲害了。
3.取\(log\),用\(1e-9\)的精度判斷是否相等即可


code:

#include <cstdio>
#include <vector>
#include <map>
#define ll long long
using namespace std;
const ll N=500010;
const int mod=19260817;
ll n,used[N];
ll f[N],c[N];
vector <ll > g[N];
map <ll,ll > m;
void dfs(ll now)
{
    used[now]=1;
    ll siz=g[now].size();
    for(int i=0;i<siz;i++)
    {
        ll v=g[now][i];
        if(!used[v])
        {
            if(now==1) f[v]=f[now]*siz%mod;
            else f[v]=f[now]*(siz-1)%mod;
            dfs(v);
        }
    }
}

int main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",c+i);
    ll u,v;
    for(int i=1;i<n;i++)
    {
        scanf("%lld%lld",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    f[1]=1;
    dfs(1);
    for(int i=1;i<=n;i++)
        m[(f[i]*c[i])%mod]++;
    ll m_max=0;
    for(map <ll,ll >::iterator it=m.begin();it!=m.end();it++)
        m_max=max(m_max,it->second);
    printf("%lld",n-m_max);
    return 0;
}

2018.6.2

洛谷 P3237 [HNOI2014]米特運輸 解題報告