【牛客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;
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
11-20 19:57
已编辑
某大厂 golang工程师 23.0k*16.0, 2k房补,年终大概率能拿到
点赞 评论 收藏
分享
Yushuu:你的确很厉害,但是有一个小问题:谁问你了?我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了😆
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务