ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

牛客小白月赛22

2020-02-23 14:39:44  阅读:261  来源: 互联网

标签:22 int 小白月赛 t2 t1 牛客 ans maxm 操作


牛客小白月赛22


B.树上子链

题意:

给定一棵树 T ,树 T 上每个点都有一个权值。
定义一颗树的子链的大小为:这个子链上所有结点的权值和 。
请在树 T 中找出一条最大的子链并输出。

思路:

类似树形dp求树的直径。
d(i)表示以点i到以i为根的子树任意一点的最大距离
dfs过程中我们记录子树中的最大和次大。
1.如果最长链不经过父节点那条边,那么最大和次大连接就是经过当前点的最长链。
2.如果最长链经过父节点那条边,那么在回溯到父节点那层时就能计算出正确的最长链。
所以不考虑父节点并不失完备性。

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
vector<int>g[maxm];
int a[maxm];
int d[maxm];
int ans=-1e18;//因为有负点权,所以ans要初始化为-inf
void dfs(int x,int fa){
    int t1=0,t2=0;//t1,t2记录最大和次大
    for(int v:g[x]){
        if(v==fa)continue;
        dfs(v,x);
        if(d[v]>t1){
            t2=t1;
            t1=d[v];
        }else if(d[v]>t2){
            t2=d[v];
        }
    }
    d[x]=t1+a[x];
    ans=max(ans,t1+t2+a[x]);
}
signed main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs(1,-1);
    cout<<ans<<endl;
    return 0;
}

C.交换游戏

题意:

给一个长度为12的只含o和-的串
一种操作是将串中的子串oo-变成–o
一种操作是将串中的子串-oo变成o–
问无限次操作之后串中的o最少为多少

思路:

每次操作之后会得到一个新的序列,接下来就是要计算新序列的最小值。
因此可以发现原串的最小值就是其一步操作所能得到的所有新串的最小值。
一步操作得到的新串的最小值又是新新串中的最小值…因此记忆化搜索取min即可。
因为串的长度只有12,所以可以状压为二进制串,方便操作。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1<<12;
bool mark[maxm];
int ans[maxm];
void solve(int x){
    if(mark[x])return ;
    mark[x]=1;
    for(int j=0;j<12;j++)ans[x]+=(x>>j&1);//初始化答案为1的数量
    for(int k=2;k<12;k++){
        int i=k-2,j=k-1;
        if((x>>i&1)&&(x>>j&1)&&!(x>>k&1)){//oo-
            int temp=x-(1<<i)-(1<<j)+(1<<k);
            solve(temp);
            ans[x]=min(ans[x],ans[temp]);
        }else if(!(x>>i&1)&&(x>>j&1)&&(x>>k&1)){//-oo
            int temp=x+(1<<i)-(1<<j)-(1<<k);
            solve(temp);
            ans[x]=min(ans[x],ans[temp]);
        }
    }
}
signed main(){
    for(int i=0;i<(1<<12);i++)solve(i);//直接预处理所有情况
    int T;
    cin>>T;
    while(T--){
        string s;
        cin>>s;
        int x=0;
        for(int j=0;j<12;j++){
            if(s[j]=='o'){
                x|=(1<<j);
            }
        }
        cout<<ans[x]<<endl;
    }
    return 0;
}

H.货物种类

题意:

给n和m表示n个谷仓m种操作
每种操作(L,R,d),表示吧区间[L,R]这段的谷仓都加入货物d
问m次操作之后那个谷仓的货物最多
n<=1e5,m<=1e5,d<=1e9

思路:

差分,和单纯的数加减法的差分差不多。
区别仅在于每个位置可能添加或者减少多个数,不能和加减法一样直接操作。
需要开两个数组存下每个位置要添加或者减少的数。
详见代码。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
vector<int>add[maxm];//添加
vector<int>del[maxm];//减少
map<int,int>mark;//记录每个数出现次数
signed main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int l,r,d;
        cin>>l>>r>>d;
        add[l].push_back(d);
        del[r+1].push_back(d);
    }
    int ans=0;
    int ma=0;
    int now=0;
    for(int i=1;i<=n;i++){
        for(int v:add[i]){
            mark[v]++;
            if(mark[v]==1)now++;
        }
        for(int v:del[i]){
            mark[v]--;
            if(mark[v]==0)now--;
        }
        if(now>ma){
            ma=now;
            ans=i;
        }
    }
    cout<<ans<<endl;
    return 0;
}

I.工具人


我到底在干嘛 发布了402 篇原创文章 · 获赞 33 · 访问量 2万+ 私信 关注

标签:22,int,小白月赛,t2,t1,牛客,ans,maxm,操作
来源: https://blog.csdn.net/weixin_44178736/article/details/104453724

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有