[九省联考2018] 秘密袭击coat

题目描述:

QAQ…

题目分析:

正解需要:
1:整体DP…
2:多项式初步
3:拉格朗日插值法
4:生成函数
5:线段树合并
好的,全不会
看上面那堆算法,很多都是常数很大的东西,那么我们是不是可以用暴力算法卡卡常卡过去呢?
可以
方法来自于SD青岛二中神犇赛后讲解,暴力踩标算Orz
枚举一个点为第K大值的点,树上大于该点的点标为1,小于该点的标为0
那么我们可以用一个树上依赖背包来求解一下和为K的联通块的个数,贡献即为 num*val[i]
复杂度大概为 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;
}

猜你喜欢

转载自blog.csdn.net/qq_35914587/article/details/80268620