【牛客IOI周赛16-普及组】补题,树形DP

A

签到题,本质上是求

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MOD=1e9+7;
int main()
{
    int n;ll ans=1;cin>>n;
    while(n){
        ans=(ans%MOD*n%MOD)%MOD;
        n--;
    }
    cout<<ans;
}

B 猜数---排序和不排序两种做法

原数组排序,从前以后依次加上,一直加到大于等于给定m 。相当于一种贪心,从最多的差值开始加,一直加到大于m此时遍历的数就为最少改动数。 时间

#include <bits/stdc++.h>
using namespace std;

#define ll long long
int num[1000005];
int main(){
    int n,m;
    cin>>n>>m;
    ll sum=0;
    for(int i=0;i<n;++i){
        cin>>num[i];
        sum+=num[i];
    }
    sort(num,num+n);
    int tmp=sum;int ans=1;
    for(int i=0;i<n;++i){
        tmp+=9-num[i];
        if(tmp>=m){
            break;
        }else ans++;
    }
    cout<<ans;
}

IOI赛制要求执行效率,考虑不排序做法:
上面做法排序是为了遵循先加上比较大的差值,那么可以先统计原数组0-9的个数,然后枚举差值即可,常数时间复杂度。

#include <bits/stdc++.h>
using namespace std;
int cnt[10];
int n,m,ans,sum;

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int x;cin>>x;
        cnt[x]++,sum+=x;
    }
    for(int i=0;i<10;i++){
        int d=9-i;//枚举差值,差值无非就是0~9
        int now=cnt[i]*d;
        if(sum+now<m) sum+=now,ans+=cnt[i];
        else{
            ans+=(m-sum)%d==0?(m-sum)/d:(m-sum)/d+1;
            break;
        }
    }
    printf("%d\n",ans);
    return 0;
}

C

找规律,推出递推公式:
看了官方题解觉得这个题出的真不错——f[i]表示i*i的矩阵的方法数

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;

#define ll long long
const int MOD = 1e9+7;
int nn,n;
ll f[100005];
int main()
{
    cin>>n;
    f[0]=1;f[1]=1;
    for(int i=2;i<=n;++i){
        f[i]=(f[i-1]%MOD+(i-1)%MOD*f[i-2]%MOD)%MOD;
    }
    cout<<f[n]%MOD;
}

D

https://ac.nowcoder.com/acm/contest/5389/D

参考大佬题解https://blog.nowcoder.net/n/9672836159594b519ceebcdb658ab6c2 表示 u 这个节点,最长链小于等于j的最小代价。
转移过程中要用tmp[i]来保存dp[u][i]过程值
转移方程:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e3+7;
const int INF = 0x3f3f3f3f;
int a[N],f[N][N],tmp[N];

vector<int> e[N];
int n,l;
void dfs(int u,int fa){
    f[u][0]=a[u]; //删除自己
    for(auto child : e[u])if(child!=fa){
        dfs(child,u);
        f[u][0]+=*min_element(f[child],f[child]+l); //删除自己 同时子树最长链也小于等于l
        for(int i=1; i<l; ++i)
            tmp[i]=f[u][i],f[u][i]=INF; 
        for(int i=1; i<l;++i){  //不删除自己
            for(int j=0; j<l; ++j){ //子树最长链满足小于等于j
                if(i+j<l) f[u][max(i,j+1)]=min(f[u][max(i,j+1)],tmp[i]+f[child][j]);
                else break;
            }
        }
    }
}

int main(){
    cin>>n>>l;
    for(int i=1;i<=n;++i) cin>>a[i];
    for(int i=1;i<n;++i){
        int u,v;cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1,0);
    printf("%d\n",*min_element(f[1],f[1]+l));
    return 0;
}
全部评论

相关推荐

想去夏威夷的小哥哥在度假:5和6才是重点
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务