牛客小白月賽22題解(部分)

鏈接:https://ac.nowcoder.com/acm/contest/4462
來源:nowcoder

B 樹上子鏈(樹的直徑)

  思路:類似於樹的直徑問題,如果權值都爲正值我們可以直接兩次 bfsbfs 即可,現在權值有賦值,我們可以用 dpdp 來解決,dp[i]dp[i] 表示從 ii 結點出發向下走的最長子鏈的長度(我們以 11 號結點作爲根結點)。直接 dfsdfs 更新 dpdp 的值即可。

#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 方塊塗色(貪心)

  思路:簽到題,直接塗前 aa 行和前 bb 列,然後計算剩下沒有塗色的即可。

#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 累乘數字(簽到)

  思路:在 nn 後面加 2d2d00 即可,最近遇到大數比較多,沒有思索直接就高精度乘單精度來計算了。

#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 貨物種類(差分)

  思路:分別用 vetorvetor 記錄某個區間放入了什麼數據,l[i]l[i] r[i]r[i] 記錄區間的頭和尾放入的貨物 ididvisvis 用來表示編號爲 ii 的物品的數量。遍歷 [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(大數加法)

  思路:此題換成了保證沒有前導 00 的情況,所以直接分離出 AABB進行大數加法即可。多組數據,注意數組的清空問題。

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章