牛客小白月赛22题解(部分)

链接:https://ac.nowcoder.com/acm/contest/4462
来源:nowcoder

B 树上子链(树的直径)

  思路:类似于树的直径问题,如果权值都为正值我们可以直接两次 b f s bfs 即可,现在权值有赋值,我们可以用 d p dp 来解决, d p [ i ] dp[i] 表示从 i i 结点出发向下走的最长子链的长度(我们以 1 1 号结点作为根结点)。直接 d f s dfs 更新 d p dp 的值即可。

#include<bits/stdc++.h>
using namespace std;
 
#define pb push_back
 
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+10;
ll dp[maxn],ans=-inf;
int w[maxn];
 
vector<int>G[maxn];
 
void dfs(int u,int fa){
    dp[u]=w[u];
    for(auto v:G[u]){
        if(v==fa) continue;
        dfs(v,u);
        ans=max(ans,dp[u]+dp[v]);
        dp[u]=max(dp[u],dp[v]+w[u]);
    }
    ans=max(ans,dp[u]);
}
 
int main(){
    int n; scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    for(int i=1;i<=n-1;i++){
        int u,v; scanf("%d%d",&u,&v);
        G[u].pb(v); G[v].pb(u);
    }
    dfs(1,0);
    printf("%lld\n",ans);
    return 0;
}

D 收集纸片(dfs)

  思路:我们可以注意到纸片的数量比较少,所以我们直接搜索出每一种情况作出判断即可。

#include<bits/stdc++.h>
using namespace std;
 
const int maxn=15;
int x[maxn],y[maxn];
bool vis[maxn];
 
int n,ans=INT_MAX;
 
int dis(int i,int j){
    return abs(x[i]-x[j])+abs(y[i]-y[j]);
}
 
void dfs(int now,int Min,int cnt){
    if(cnt==n){
        ans=min(ans,Min+dis(now,0));
        return ;
    }
    for(int i=1;i<=n;i++){
        if(vis[i]) continue;
        vis[i]=true;
        dfs(i,Min+dis(now,i),cnt+1);
        vis[i]=false;
    }
}
 
int main(){
    int T; scanf("%d",&T);
    while(T--){
        int r,c; scanf("%d%d",&r,&c);
        scanf("%d%d",&x[0],&y[0]);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
        dfs(0,0,0);
        printf("The shortest path has length %d\n",ans);       
    }
    return 0;
}

E 方块涂色(贪心)

  思路:签到题,直接涂前 a a 行和前 b b 列,然后计算剩下没有涂色的即可。

#include<bits/stdc++.h>
using namespace std;
 
int main(){
    long long n,m,a,b;
    while(cin>>n>>m>>a>>b){
        cout<<n*m-(a*m+b*n-a*b)<<endl;
    }
    return 0;
}

F 累乘数字(签到)

  思路:在 n n 后面加 2 d 2d 0 0 即可,最近遇到大数比较多,没有思索直接就高精度乘单精度来计算了。

#include<bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const int maxn=1e5+10;
int ans[maxn];
 
int main(){
    int n,d;
    while(~scanf("%d%d",&n,&d)){
        int len=0;
        ans[0]=1; len=1;
        for(int i=0;i<len;i++) ans[i]*=n;
        for(int i=0;i<len;i++){
            ans[i+1]+=ans[i]/10;
            ans[i]%=10;
        }
        while(ans[len]){
                ans[len+1]+=ans[len]/10;
                ans[len]%=10;
                len++;
            }
        for(int q=1;q<=d;q++){
            for(int i=0;i<len;i++) ans[i]*=100;
            for(int i=0;i<len;i++){
                ans[i+1]+=ans[i]/10;
                ans[i]%=10;
            }
            while(ans[len]){
                ans[len+1]+=ans[len]/10;
                ans[len]%=10;
                len++;
            }
        }
        for(int i=len-1;i>=0;i--) printf("%d",ans[i]);
        puts("");
        for(int i=0;i<len;i++) ans[i]=0;
    }
    return 0;
}

G 仓库选址(枚举)

  思路:由于数据范围比较小,直接枚举算出在每一个点的值,最后找到最小值就行了。

#include<bits/stdc++.h>
using namespace std;
 
#define pb push_back
 
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e2+10;
int a[maxn][maxn];
 
struct Node{
    int x,y;
    Node(){}
    Node(int x,int y):x(x),y(y){}
};
 
ll dis(Node node1,Node node2){
    return abs(node1.x-node2.x)+abs(node1.y-node2.y);
}
 
int main(){
    int T; scanf("%d",&T);
    while(T--){
        ll ans=inf;
        int n,m; scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                Node node=Node(i,j);
                ll res=0;
                for(int x=1;x<=m;x++){
                    for(int y=1;y<=n;y++){
                        res+=dis(node,Node(x,y))*a[x][y];
                    }
                }
                ans=min(ans,res);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

H 货物种类(差分)

  思路:分别用 v e t o r vetor 记录某个区间放入了什么数据, l [ i ] l[i] r [ i ] r[i] 记录区间的头和尾放入的货物 i d id v i s vis 用来表示编号为 i i 的物品的数量。遍历 [ 1 , n ] [1,n] 用差分的方法来一次计算每个仓库放了多少种货物。

#include<bits/stdc++.h>
using namespace std;
 
#define pb push_back
 
const int maxn=1e5+10;
vector<int>l[maxn],r[maxn];
map<int,int>vis;
 
int main(){
    int n,m; scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int l1,r1,d; scanf("%d%d%d",&l1,&r1,&d);
        l[l1].pb(d); r[r1+1].pb(d);
    }
    int ans=-1,inx=-1,cnt=0;
    for(int i=1;i<=n;i++){
        for(auto j:l[i]){
            if(!vis[j]) cnt++;//当前货物没有数量为 0,货物需要加一种
            vis[j]++;//该仓库当前货物数量
        }
        for(auto j:r[i]){
            vis[j]--;//该仓库当前货物数量
            if(!vis[j]) cnt--;//当前货物没有了
        }
        //cout<<cnt<<" ";
        if(ans<cnt){
            ans=cnt;
            inx=i;
        }
    }
    //cout<<endl;
    printf("%d\n",inx);
    return 0;
}

J 计算A+B(大数加法)

  思路:此题换成了保证没有前导 0 0 的情况,所以直接分离出 A A B B 进行大数加法即可。多组数据,注意数组的清空问题。

#include<bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const int maxn=1e5+10;
char str[maxn],a[maxn],b[maxn];
int c[maxn],d[maxn],ans[2*maxn];
 
void cal(){
    memset(c,0,sizeof(c));
    memset(d,0,sizeof(d));
    memset(ans,0,sizeof(ans));
    int lena=strlen(a),lenb=strlen(b);
    for(int i=0;i<lena;i++) c[i]=a[lena-i-1]-'0';
    for(int i=0;i<lenb;i++) d[i]=b[lenb-i-1]-'0';
    int len=max(lena,lenb);
    for(int i=0;i<len;i++){
        ans[i]+=c[i]+d[i];
        if(ans[i]>9){
            ans[i]-=10;
            ans[i+1]++;
        }
    }
    len=ans[len]?len+1:len;
    for(int i=len-1;i>=0;i--) printf("%d",ans[i]);
    puts("");
}
 
int main(){
    int T; scanf("%d",&T);
    while(T--){
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        scanf("%s",str);
        int n=strlen(str),cnt1=0,cnt2=0;
        int inx=-1;
        for(int i=0;i<n;i++){
            if(str[i]<='9'&&str[i]>='0') a[cnt1++]=str[i];
            if(str[i]=='+') { inx=i;break; }
        }
        if(inx==-1||inx==n-1||inx==0){
            puts("skipped");
            continue;
        }
        bool flag=true;
        for(int i=inx+1;i<n;i++){
            if(str[i]<='9'&&str[i]>='0') b[cnt2++]=str[i];
            else {
                flag=false;
                break;
            }
        }
        //cout<<cnt1<<" "<<cnt2<<endl;
        if(flag){
            //puts(a); puts(b);
            cal();
        }else{
            puts("skipped");
        }
    }
    return 0;
}
发布了166 篇原创文章 · 获赞 68 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42217376/article/details/104467374