1. 程式人生 > >[亂搞]JZOJ 5913 林下風氣

[亂搞]JZOJ 5913 林下風氣

clu 存在 ios opened int 相減 bec long printf

Description

裏口福因有林下風氣,帶領全國各地高校掀起了一股AK風,大家都十分癡迷於AK。裏口福為了打擊大家的自信心,出了一道自以為十分困難的題目。
裏口福有一棵樹,第i個節點上有點權ai,他的問題就是這棵樹中有多少個不同的連通塊滿足連通塊的最大值與最小值之差=k,兩個連通塊不同當且僅當至少存在一個節點在一個連通塊中出現而另一個連通塊中沒有出現。
癡迷於AK的你馬上接下這道題目,在裏口福狂妄的笑聲中,你切掉這道題的決心更加堅定了,現在就差你的代碼了。

Input

第一行兩個整數n,k,表示樹的大小以及題目中的k。
第二行n個整數,第i個整數表示ai。
接下來n-1行,每行兩個整數x,y表示樹邊(x,y)。

Output

一行一個整數,表示答案,答案對19260817取模。

Sample Input

5 3
1 2 3 4 5
1 2
1 3
2 4
2 5

Sample Output

4
 

Data Constraint

對於30%的數據,n<=22
對於另外20%的數據,樹是一條鏈
對於另外20%的數據,ai只有0和1兩種
對於100%的數據,N<=3333,0<=ai<=N,K>=0

分析

我們把差值小於等於k的方案數和插值小於k的方案數相減就是等於k的方案數嘛

然後我們每次對以i為根的子樹求方案數,但是有問題:如果值相等,可能會算多次,所以我們只算比編號根大的點,就避免了重復。

技術分享圖片
#include <iostream>
#include <cstdio>
using namespace std;
const int N=3333+10;
const int P=19260817;
struct Edge {
    int u,v,nx;
}g[2*N];
int cnt,list[N];
int w[N];
int n,k;

void Add(int u,int v) {
    g[++cnt].u=u;g[cnt].v=v;g[cnt].nx=list[u];list[u]=cnt;
}

int
Dfs(int u,int fa,int mxid) { long long ans=1; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa&&w[mxid]>=w[g[i].v]&&w[mxid]-w[g[i].v]<=k&&(mxid<g[i].v||w[mxid]!=w[g[i].v])) (ans*=1ll*Dfs(g[i].v,u,mxid)+1)%=P; return ans; } int main() { freopen("lkf.in","r",stdin); freopen("lkf.out","w",stdout); scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) scanf("%d",&w[i]); for (int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); Add(u,v);Add(v,u); } int smaller_or_equals_k=0,smaller_or_equals_k_1=0; for (int i=1;i<=n;i++) (smaller_or_equals_k+=Dfs(i,-1,i))%=P; if (k) { k--; for (int i=1;i<=n;i++) (smaller_or_equals_k_1+=Dfs(i,-1,i))%=P; } printf("%d",(smaller_or_equals_k-smaller_or_equals_k_1+P)%P); }
View Code

[亂搞]JZOJ 5913 林下風氣