JZOJ 5400. 【NOIP2017提高A组模拟10.7】Repulsed
Description
小w 心里的火焰就要被熄滅了。
簡便起見,假設小w 的內心是一棵n -1 條邊,n 個節點的樹。
現在你要在每個節點里放一些個滅火器,每個節點可以放任意多個。
接下來每個節點都要被分配給一個至多k 條邊遠的滅火器,每個滅火器最多能分配給s 個節點。
至少要多少個滅火器才能讓小w 徹底死亡呢?
Input
第一行三個整數n, s, k。
接下來n -1行每行兩個整數表示一條邊。
Output
一行一個整數表示答案
Sample Input
10 10 3
1 8
2 3
1 5
2 4
1 2
8 9
8 10
5 6
5 7
Sample Output
1
Data Constraint
對于20% 的數據滿足n <= 100, k <= 2。
對于另外20% 的數據滿足k = 1。
對于另外20% 的數據滿足s = 1。
對于100% 的數據滿足n <= 10^5, k <= 20, s <= 10^9。
Solution
貪心的思想:滅火器從底下開始放,肯定是越上越好(能更好地影響上面)。
設 F[x][i] 表示以 x 為根的子樹中與 x 距離為 i 的滅火器的剩余滅火數量。
設 G[x][i] 表示以 x 為根的子樹中與 x 距離為 i 的節點中尚未被滅的數量。
那么顯然, x 的信息可以通過 x 的兒子節點更新。
首先,G[x][0]=1 (自己尚未覆蓋)。
如果 G[x][k] 有值,那么 x 這個點必須放滅火器,不然之后就沒法影響到了,同時要。
于是在 x 處填滅火器直到滿足完 G[x][k] ——再賦值 F[x][0] 。
接著我們要可以匹配 F[x][i] 和 G[x][j]?(i+j=k) ,同時減去之間的最小值。
因為處理完 x 就會到 x 的父親,相對的距離就要加 2 ,于是 i+j=k?1 也要匹配。
那么最后還要匹配 F[1][i] 和 G[1][j] 的值。
答案要加上 G[1][i] 那些沒能匹配的值(需加放滅火器)。
時間復雜度 O(N?K) 。
Code
#include<cstdio> using namespace std; const int N=1e5+1; int n,s,k,tot,ans,num; int first[N],next[N<<1],en[N<<1]; int f[N][21],g[N][21]; inline int read() {int X=0,w=1; char ch=0;while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();return X*w; } inline void insert(int x,int y) {next[++tot]=first[x];first[x]=tot;en[tot]=y; } inline int min(int x,long long y) {return x<y?x:y; } inline int get(int x) {return !x?0:(x-1)/s+1; } inline void dfs(int x,int y) {for(int i=first[x];i;i=next[i])if(en[i]!=y){dfs(en[i],x);for(int j=1;j<=k;j++){f[x][j]=min(f[x][j]+f[en[i]][j-1],n);g[x][j]+=g[en[i]][j-1];}}g[x][0]=1;if(g[x][k]){ans+=num=get(g[x][k]);f[x][0]=min(n,(long long)s*num);}for(int i=0;i<=k;i++){int j=k-i;num=min(f[x][i],g[x][j]);f[x][i]-=num;g[x][j]-=num;}for(int i=0;i<k;i++){int j=k-1-i;num=min(f[x][i],g[x][j]);f[x][i]-=num;g[x][j]-=num;} } int main() {n=read(),s=read(),k=read();for(int i=1;i<n;i++){int x=read(),y=read();insert(x,y);insert(y,x);}dfs(1,0);for(int i=k;i;i--)for(int j=0;j<=k-i;j++){num=min(f[1][i],g[1][j]);f[1][i]-=num;g[1][j]-=num;}num=0;for(int i=0;i<=k;i++) num+=g[1][i];ans+=get(num);printf("%d",ans);return 0; }總結
以上是生活随笔為你收集整理的JZOJ 5400. 【NOIP2017提高A组模拟10.7】Repulsed的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 5398. 【NOIP2017
- 下一篇: JZOJ 5401. 【NOIP2017