SHOI2015 聚变反应炉 题解
SHOI2015 聚变反应炉 题解
神秘数据分治题。
看 \(c\le 1\) 的点,发现先遍历 \(c=1\) 再遍历 \(c=0\) 的收益最高,贪心做即可。
看 \(n\le 2000\) 的点,发现 \(c\le 5\) 很有性质的样子,但是瞪不出来。发现可能是一个 \(O(n^2)\) 的 dp,设\(dp_{i,0/1}\) 为这个点先被激活/它的父亲先被激活的子树里的最小的代价。
然而这个不是很好转移,对于它的儿子与这个节点的激活顺序是对 dp 值是没有影响的,因为 \(c\le 5\) ,考虑一个背包,\(f_i\) 表示这个点被贡献了 \(i\) 次,最小的代价。这个直接由儿子的 dp 转移而来即可。接着 dp 就可以通过 \(f_i\) 来转移,注意有可能会被减到负数,这时需要判断一下。
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 1E5 + 5;
int n, m, d[N], c[N];
int mx = 0;
vector<int> e[N];
int ans;
int dp[2005][2];
int tmp[2][10005],sum;
using namespace std;
namespace ly
{
namespace IO
{
#ifndef LOCAL
constexpr auto maxn=1<<20;
char in[maxn],out[maxn],*p1=in,*p2=in,*p3=out;
#define getchar() (p1==p2&&(p2=(p1=in)+fread(in,1,maxn,stdin),p1==p2)?EOF:*p1++)
#define flush() (fwrite(out,1,p3-out,stdout))
#define putchar(x) (p3==out+maxn&&(flush(),p3=out),*p3++=(x))
class Flush{public:~Flush(){flush();}}_;
#endif
namespace usr
{
template<typename type>
inline type read(type &x)
{
x=0;bool flag(0);char ch=getchar();
while(!isdigit(ch)) flag^=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return flag?x=-x:x;
}
template<typename type>
inline void write(type x)
{
x<0?x=-x,putchar('-'):0;
static short Stack[50],top(0);
do Stack[++top]=x%10,x/=10;while(x);
while(top) putchar(Stack[top--]|48);
}
inline char read(char &x){do x=getchar();while(isspace(x));return x;}
inline char write(const char &x){return putchar(x);}
inline void read(char *x){static char ch;read(ch);do *(x++)=ch;while(!isspace(ch=getchar())&&~ch);}
template<typename type>inline void write(type *x){while(*x)putchar(*(x++));}
inline void read(string &x){static char ch;read(ch),x.clear();do x+=ch;while(!isspace(ch=getchar())&&~ch);}
inline void write(const string &x){for(int i=0,len=x.length();i<len;++i)putchar(x[i]);}
template<typename type,typename...T>inline void read(type &x,T&...y){read(x),read(y...);}
template<typename type,typename...T>
inline void write(const type &x,const T&...y){write(x),putchar(' '),write(y...),sizeof...(y)^1?0:putchar('\n');}
template<typename type>
inline void put(const type &x,bool flag=1){write(x),flag?putchar('\n'):putchar(' ');}
}
#ifndef LOCAL
#undef getchar
#undef flush
#undef putchar
#endif
}using namespace IO::usr;
}using namespace ly::IO::usr;
inline void tomin(int &x,int y){
if(x>y)x=y;
}
void dfs(int u,int fa) {
int sum=0;
for(int v:e[u]) {
if(v==fa)continue;
sum+=c[v];
dfs(v,u);
}
for(int i=0;i<=sum;i++)tmp[0][i]=1e9;
tmp[0][0]=0;
int now=0;
for(int v:e[u]) {
if(v==fa)continue;
now^=1;
memset(tmp[now],0x3f,sizeof tmp[now]);
for(int i=0; i<=sum-c[v]; i++) {
tomin(tmp[now][i],tmp[now^1][i]+dp[v][1]);
tomin(tmp[now][i+c[v]],tmp[now^1][i]+dp[v][0]);
}
}
memset(dp[u],0x3f,sizeof dp[u]);
for(int i=0; i<=sum; i++) {
tomin(dp[u][0],max(tmp[now][i],tmp[now][i]-i+d[u]));
tomin(dp[u][1],max(tmp[now][i],tmp[now][i]-i+d[u]-c[fa]));
}
}
int main() {
read(n);
int t=0;
for (int i = 1; i <= n; i++) read(d[i]),sum+=d[i];
for (int i = 1; i <= n; i++) read(c[i]), mx = max(c[i], mx),t+=c[i];
if(t==mx*n){
put(sum-(n-1)*mx);
return 0;
}
for(int i=1,u,v; i<n; i++) {
read(u),read(v);
e[u].push_back(v);
e[v].push_back(u);
}
if(mx<=1) {
for(int i=1; i<=n; i++)
if(c[i]==1) {
ans+=d[i];
d[i]=0;
for(int j:e[i])
d[j]--;
}
for(int i=1; i<=n; i++)
if(d[i]>0)ans+=d[i];
put(ans);
return 0;
}
dfs(1,0);put(dp[1][0]);
return 0;
}

浙公网安备 33010602011771号