2020牛客寒假算法基礎訓練營3題解

寫在前面:這場的題目感覺比前兩場的難,最後苟了個七題,BEJ估計明天再補吧。現在更新一下已經過了的七道題。

A-牛牛的DRB迷宮I

題意:給出一個nmn*m的迷宮,每一格有三種情況,分別是DD向下移動,RR向右移動,BB可以向下也可以向右移動。
題解:顯然的dp題。當a[i][j]=Da[i][j]=Ddp[i+1][j]+=dp[i][j]dp[i+1][j]+=dp[i][j],當a[i][j]=Ra[i][j]=Rdp[i][j+1]+=dp[i][j]dp[i][j+1]+=dp[i][j],當a[i][j]=Ba[i][j]=Bdp[i][j+1]+=dp[i][j],dp[i+1][j]+=dp[i][j]dp[i][j+1]+=dp[i][j],dp[i+1][j]+=dp[i][j]。最後輸出dp[n][m]dp[n][m]即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
ll f[100][100];
int n,m;
char s[100][100];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)scanf("%s",&s[i]);
    f[0][0]=1ll;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(s[i][j]=='D')f[i+1][j]=(f[i+1][j]+f[i][j])%mod;
            else if(s[i][j]=='R')f[i][j+1]=(f[i][j+1]+f[i][j])%mod;
            else if(s[i][j]=='B')f[i+1][j]=(f[i+1][j]+f[i][j])%mod,f[i][j+1]=(f[i][j+1]+f[i][j])%mod;
    printf("%lld\n",f[n-1][m-1]);
    return 0;
}

C-牛牛的數組越位

題意:題目描述了一下數組越界的概念,具體自己看題目介紹吧。
題解:按照題意模擬即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e7+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int n,m,p;
int G[1010][1010];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&m,&p);
        int fflag=0,ffflag=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)G[i][j]=0;
        while(p--){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            int k=m*x+y;
            if(!ffflag){
                if(k<0 || k>=n*m){ffflag=1;continue;}
                if(x<0 || y<0 || x>=n || y>=m){fflag=1;}
                int yy=k%m,xx=k/m;
                G[xx][yy]=z;
            }
        }
        if(ffflag){
            puts("Runtime error");
            continue;
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<m-1;j++)printf("%d ",G[i][j]);
            printf("%d\n",G[i][m-1]);
        }
        if(fflag)puts("Undefined Behaviour");
        else puts("Accepted");
    }
    return 0;
}

D-牛牛與二叉樹的數組存儲

題意:題目描述了一下數組存儲二叉樹的概念,具體自己看題目介紹即可。
題解:按照題意模擬即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int n,a[2*maxn],f[maxn*2],sum;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),f[a[i]]=i;
    for(int i=1;i<=n;i++)if(a[i]!=-1)sum++;
    for(int i=n+1;i<=n*2+1;i++)a[i]=-1;
    a[0]=-1;
    printf("The size of the tree is %d\n",sum);
    printf("Node %d is the root node of the tree\n",a[1]);
    for(int i=1;i<=sum;i++){
        printf("The father of node %d is %d, the left child is %d, and the right child is %d\n",i,a[f[i]/2],a[f[i]*2],a[f[i]*2+1]);
    }
    return 0;
}

F-牛牛的Link Power I

題意:給出一個長度爲n的01串,設s[u]=s[v]=1s[u]=s[v]='1',則答案需要加上dis(uv)dis(u-v),算出所有的1對對答案的貢獻即可。
題解:可以亂搞,方法很多。開一個數組記錄所有1的位置,記錄一下所有的和sum,再用一個cnt表示當前有多少個1,每次對答案的貢獻就是當前的a[i]*cnt-sum。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int n,cnt,num;
ll sum,ans;
int q[maxn];
char a[maxn];
int main(){
    scanf("%d",&n);
    scanf("%s",&a);
    for(int i=0;i<n;i++)
        if(a[i]=='1'){
            q[++cnt]=i;
            sum=sum+1ll*i;
        }
    for(int i=cnt;i>0;i--){
        sum=sum-1ll*q[i];num++;
        ans=(ans+1ll*(cnt-num)*q[i]-sum)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

H-牛牛的k合因子數

題意:一個正整數,如果有k個合數因子則被稱爲k合因子數。m個詢問,每次問1~n中有多少個k合因子數。
題解:篩法。先篩出1e5全部的素數,然後再用篩法類似的累加一下貢獻即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int f[maxn],ans[maxn],a[maxn];
int n,m,k;
int main(){
    for(int i=2;i<=100000;i++)
        if(!f[i])
            for(int j=i*2;j<=100000;j+=i)f[j]++;
    for(int i=2;i<=100000;i++)
        if(f[i])
            for(int j=i;j<=100000;j+=i)a[j]++;
//  printf("%d\n",a[20]);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)ans[a[i]]++;
    while(m--){
        scanf("%d",&k);
        printf("%d\n",ans[k]);
    }
    return 0;
}

G-牛牛的Link Power II

題意:F題題意,但是帶修。保證一定是將1改成0,0改成1。每次輸出修改後的總答案。
題解:先計算出答案,對於維護我們使用線段樹,維護區間1的個數和1的位置總和。若將0變1相當於增加一波貢獻,若將1變0相當於減去一波貢獻。假設k1和k2分別是[1,pos-1],[pos+1,n]的區間結點。對於答案就應該分別加上或減去posk1.numk1.sum+k2.sumposk2.numpos*k1.num-k1.sum+k2.sum-pos*k2.num

#include "stdio.h"
#include "string.h"
#include "iostream"
#include "algorithm"
#include "stack"
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
struct Node{
    ll sum;
    int num;
}s[maxn*4],res;
stack<int>q;
struct arr{
    int pos,val;
}a[maxn];
Node cmp(Node a,Node c){
    Node k;
    k.num=(a.num%mod+c.num%mod)%mod;
    k.sum=(a.sum%mod+c.sum%mod)%mod;
    return k;
}
void pushup(int node){
    s[node].sum=(s[node<<1].sum%mod+s[node<<1|1].sum%mod)%mod;
    s[node].num=(s[node<<1].num%mod+s[node<<1|1].num%mod)%mod;
    return;
}
void build(int l,int r,int node){
    if(l==r){
        s[node].num=a[l].pos;
        s[node].sum=a[l].val;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,node<<1);
    build(mid+1,r,node<<1|1);
    pushup(node);
}
void update(int L,int x,int l,int r,int node){
    if(l==r){
        if(x==1)s[node].sum=L;
        if(x==0)s[node].sum=0;
        s[node].num=x;
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid)update(L,x,l,mid,node<<1);
    else update(L,x,mid+1,r,node<<1|1);
    pushup(node);
}
Node query(int L,int R,int l,int r,int node){
    if(l>=L && r<=R)return s[node];
    int mid=(l+r)>>1;
    Node res;res.num=0;res.sum=0;
    if(L<=mid) res=cmp(res,query(L,R,l,mid,node<<1));
    if(R>mid)  res=cmp(res,query(L,R,mid+1,r,node<<1|1));
    return res;
}
char t[maxn];
int n,m,cnt;
ll ans,sum;
int main(){
    scanf("%d",&n);
    scanf("%s",&t);
    scanf("%d",&m);
    for(int i=0;i<n;i++){
        if(t[i]=='0')continue;
        sum=(sum+1ll*i)%mod;
        cnt++;
        q.push(i);
        a[i+1].pos=1;
        a[i+1].val=i+1;
    }
    while(!q.empty()){
        int k=q.top();q.pop();
        sum-=k*1ll;
        cnt--;
        ans=(ans+1ll*cnt*k-sum)%mod;
    }
    build(1,n,1);
    printf("%lld\n",ans);
    while(m--){
        int opt,pos;
        scanf("%d%d",&opt,&pos);
        if(opt==1){
            update(pos,1,1,n,1);
            Node k1,k2;
            k1.sum=0ll,k1.num=0;
            k2.sum=0ll,k2.num=0;
            if(pos>1)k1=query(1,pos-1,1,n,1);
            if(pos<n)k2=query(pos+1,n,1,n,1);
            ans=(ans+1ll*pos*k1.num%mod-k1.sum%mod+k2.sum%mod-1ll*pos*k2.num%mod+2*mod)%mod;
        }
        else {
            update(pos,0,1,n,1);
            Node k1,k2;
            k1.sum=0ll,k1.num=0;
            k2.sum=0ll,k2.num=0;
            if(pos>1) k1=query(1,pos-1,1,n,1);
            if(pos<n) k2=query(pos+1,n,1,n,1);
            ans=(ans-1ll*pos*k1.num%mod+k1.sum%mod-k2.sum%mod+1ll*pos*k2.num%mod+2*mod)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

I-牛牛的漢諾塔

題意:漢諾塔,問A柱到B柱,A柱到C柱,B柱到A柱,B柱到C柱,C柱到A柱,C柱到B柱,以及總共會移動多少次。
題解:拿暴力程序打一下表,可以輕鬆的地發現總和次數爲2n12^n-1,A->B和B->C滿足一個規律,B->A和C->B滿足一個規律,A->C和C->A分別是個規律,打表出來去OEIS上翻一翻就過了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
ll a,b,c,d,e,f,sum;
ll quick(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a;
        a=a*a;
        b>>=1;
    }
    return res;
}
int n;
int main(){
    scanf("%d",&n);
    sum=quick(2,n)-1;
    if(n==1)b=1;
    if(n>1){
        ll t=n/2-1;
        a=3*t+1;
        a=(a+quick(2,2*t+3))/9;
        d=a;
    }
    if(n>2){
        ll t=(n-1)/2;
        for(int i=1;i<=t;i++)
            c=4*f+i,f=c;
        f=c;
    }
    if(n>3){
        ll t=(n-2)/2;
        e=2*(quick(4,t+1)-3*t-4)/9;
    }
    b=sum-a-c-d-e-f;
    printf("A->B:%lld\n",a);
    printf("A->C:%lld\n",b);
    printf("B->A:%lld\n",c);
    printf("B->C:%lld\n",d);
    printf("C->A:%lld\n",e);
    printf("C->B:%lld\n",f);
    printf("SUM:%lld\n",sum);
    return 0;
}

eg:剩下B題構造,E題數位dp,J題最短路明天補!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章