题目描述:
QAQ…
题目分析:
正解需要:
1:整体DP…
2:多项式初步
3:拉格朗日插值法
4:生成函数
5:线段树合并
好的,全不会
看上面那堆算法,很多都是常数很大的东西,那么我们是不是可以用暴力算法卡卡常卡过去呢?
可以
方法来自于SD青岛二中神犇赛后讲解,暴力踩标算Orz
枚举一个点为第K大值的点,树上大于该点的点标为1,小于该点的标为0
那么我们可以用一个树上依赖背包来求解一下和为K的联通块的个数,贡献即为 num*val[i]
复杂度大概为
O(n2∗k)
O
(
n
2
∗
k
)
加个取模优化,剪一下枝就可过了…
题目链接:
BZOJ 5250 无法提交,但是提供数据下载
Luogu 4365
Ac 代码:
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
const int mod=64123;
int head[2100],to[4200],net[4200],cnt;
int dp[2100][2100],d[2100];
int n,s,k,w;
inline void addedge(int u,int v)
{
cnt++;
to[cnt]=v,net[cnt]=head[u],head[u]=cnt;
}
inline void add(int &x,int y){x+=y;if(x>=mod) x-=mod;}
void dfs(int now,int fa)
{
if((d[s]<d[now])||((d[now]==d[s])&&(now<s))) for(int i=1;i<k;i++) add(dp[now][i+1],dp[fa][i]);
else for(int i=1;i<=k;i++) add(dp[now][i],dp[fa][i]);
for(int i=head[now];i;i=net[i])
if(to[i]!=fa) dfs(to[i],now);
if(fa==0) return;
for(int i=1;i<=k;i++) add(dp[fa][i],dp[now][i]);
}
int main()
{
scanf("%d%d%d",&n,&k,&w);
for(int i=1;i<=n;i++) scanf("%d",&d[i]);
for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);
int ans=0;
for(int i=1;i<=n;i++)
{
int num=0;
for(int j=1;j<=n;j++) if((d[j]>d[i])||((d[i]==d[j])&&i>j)) num++;
if(num<k-1) continue;
memset(dp,0,sizeof(dp));
dp[i][1]=1;
s=i;
dfs(i,0);
ans=(1ll*ans+1ll*d[i]*dp[i][k])%mod;
}
printf("%d\n",ans);
return 0;
}