CF816E,奇技淫巧的复杂度分析

来源:互联网 发布:vb控制台应用程序 编辑:程序博客网 时间:2024/05/29 17:38

传送门
这题作为E题考场上我想了会,然后觉得D题可以找规律更可做,规律找到一半C题被hack了,事后A题fst,C题发现是一个字符打错了,我太菜了
这题利用了求反函数这一常见的技巧,可是我并没有第一时刻就反应过来。
然后,这题用了些奇技淫巧的复杂度分析->题解,其证明大意是考虑根节点x,子树大小为n,有k个大小均为n/k的儿子,其转移代价就是O(k(k1)2(nk)2),等于O(n)真是丧心病狂

#include<bits/stdc++.h>using namespace std;const int N=5010;typedef long long ll;int n,i,xb;vector<int> e[N];ll f[N][N],a[N],b[N],m,x,dfn[N],sz[N];void dfs(int x,int fa){    sz[x]=1;    int j,k,y,z;    ll s=0;    dfn[z=++xb]=a[x];    unsigned int i;    f[x][1]=b[x];    for(i=0;i<e[x].size();++i){        y=e[x][i];        if(y!=fa){            dfs(y,x);            for(j=sz[x];j>=1;--j)                for(k=1;k<=sz[y];++k)                    if(!f[x][j+k] || f[x][j]+f[y][k]<f[x][j+k])f[x][j+k]=f[x][j]+f[y][k];            sz[x]+=sz[y];        }    }    sort(dfn+z,dfn+xb+1);    for(j=z;j<=xb;++j){        s+=dfn[j];        if(!f[x][j-z+1] || s<f[x][j-z+1])f[x][j-z+1]=s;    }}int main(){    cin>>n>>m;    for(i=1;i<=n;++i){        cin>>a[i]>>b[i];        b[i]=a[i]-b[i];        if(i>1)cin>>x,e[x].push_back(i);    }    dfs(1,0);    for(i=1;i<=n;++i)if(f[1][i]>m)break;    cout<<i-1<<endl;    return 0;}
原创粉丝点击