洛谷 P3237 [HNOI2014]米特运输 解题报告
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