2020 蓝桥杯大学 A 组模拟赛(二)(D,E(折半搜索),F水,G水,H(dp),I二分,J 线段树维护dp)

补题链接

本来都是能写题,代码没写好,导致没能拿满分 打A组的人太少了。。

D-迷宫

题目:

做法:简单bfs

我bfs 写挫了。。。

主要是这个样例:

11011

10101

10101

10001

11011

#include<bits/stdc++.h>
using namespace std;
const int N=35,M=55;
char s[N][M];
int n,m,vis[N][N],mi,ans;
struct node
{
    int x,y,t;
};
int dir[4][2]={0,1,1,0,0,-1,-1,0};
void bfs()
{
    queue<node>que;
    for(int i=1;i<=m;++i) {
        if(s[1][i]=='1') continue;
        que.push({1,i,0});
        vis[1][i]=1;
    }
    mi=3000;
    while(que.size())
    {
        node now=que.front();que.pop();
        if(now.x==n){
            if(now.t==mi) ans++;
            else if(now.t<mi) mi=now.t,ans=1;
        }
        for(int i=0;i<4;++i){
            int x=now.x+dir[i][0];
            int y=now.y+dir[i][1];
            if(x<1||y<1||x>n||y>m) continue;
            if(s[x][y]=='1')continue;
            if(now.t+1>vis[x][y]) continue;
            vis[x][y]=now.t+1;
            que.push({x,y,now.t+1});
        }
    }
}
int main()
{
    n=30,m=50;
    for(int i=1;i<=n;++i){
        scanf("%s",s[i]+1);
    }

    //--n;
    mi=0x3f3f3f3f;
    memset(vis,0x3f3f3f3f,sizeof(vis));
    bfs();

    printf("mi:%d ans:%d\n",mi,ans);
}
/*
01010101001011001001010110010110100100001000101010
00001000100000101010010000100000001001100110100101
01111011010010001000001101001011100011000000010000
01000000001010100011010000101000001010101011001011
00011111000000101000010010100010100000101100000000
11001000110101000010101100011010011010101011110111
00011011010101001001001010000001000101001110000000
10100000101000100110101010111110011000010000111010
00111000001010100001100010000001000101001100001001
11000110100001110010001001010101010101010001101000
00010000100100000101001010101110100010101010000101
11100100101001001000010000010101010100100100010100
00000010000000101011001111010001100000101010100011
10101010011100001000011000010110011110110100001000
10101010100001101010100101000010100000111011101001
10000000101100010000101100101101001011100000000100
10101001000000010100100001000100000100011110101001
00101001010101101001010100011010101101110000110101
11001010000100001100000010100101000001000111000010
00001000110000110101101000000100101001001000011101
10100101000101000000001110110010110101101010100001
00101000010000110101010000100010001001000100010101
10100001000110010001000010101001010101011111010010
00000100101000000110010100101001000001000000000010
11010000001001110111001001000011101001011011101000
00000110100010001000100000001000011101000000110011
10101000101000100010001111100010101001010000001000
10000010100101001010110000000100101010001011101000
00111100001000010000000110111000000001000000001011
10000001100111010111010001000110111010101101111000
*/

E-NP完全问题

做法:经典折半搜索 裸题了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=20;
int n=15;
map<ll,string>mp;
ll V=1019842928705602;
ll A[31]={0,
70368744177669, 105553116266503,
123145302310920, 61572651155460,
30786325577730, 15393162788865,
78065325572101, 109401406963719,
125069447659528, 62534723829764,
31267361914882, 15633680957441,
78185584656389, 109461536505863,
125099512430600, 62549756215300,
31274878107650, 15637439053825,
78187463704581, 109462476029959,
125099982192648, 62549991096324,
31274995548162, 15637497774081,
78187493064709, 109462490710023,
125099989532680, 62549994766340,
31274997383170, 15637498691585};
void dfs1(int id,ll sum, string s)
{
    if(id>15){
        mp[sum]=s;
        return ;
    }
    dfs1(id+1,sum+A[id],s+'1');
    dfs1(id+1,sum,s+'0');
}
string ans;
void dfs2(int id,ll sum, string s)
{
    if(id>30){
        if(mp.count(V-sum)!=0){
            ans=mp[V-sum]+s;
        }
        return ;
    }
    dfs2(id+1,sum+A[id],s+'1');
    dfs2(id+1,sum,s+'0');
}
int main()
{
    dfs1(1,0,"");
    dfs2(16,0,"");
    cout<<ans<<endl;
}
/*
110010000011111110101001001001
*/

F-决斗

水题一个,根据题意模拟一下就可以了。

G-学习

也是水题,排下序就可以了。

H-数字游戏

做法:dp一下就可以了,

dp[i][j]

j ==0 前i个子区间乘法为0的个数

j ==1  前i个子区间乘法大于0的个数

j ==2  前i个子区间乘法小于0的个数

维护每个负数前面正数的个数f2[2] 数组

维护每个0前面的数

细节很多,看代码的转移方程吧,我有个小细节没写好,导致坑了。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e6+10;
ll dp[N][3];//0:等于0 1:大于0 2 :于0
ll f2[2];//负数的交叉
ll pre;//前缀和
ll f0[2];//0的交叉
int n,m;

int main()
{
    scanf("%d%d",&n,&m);
    int now=0;
    for(int i=1;i<=n;++i){
        int x;
        scanf("%d",&x);
        for(int j=0;j<3;++j) dp[i][j]=dp[i-1][j];

        f0[0]++;
        if(x==0){
            f2[0]=0,f2[1]=0;
            dp[i][0]+=i;
            f0[1]=i;
        }
        else if(x>0){
            f2[now]++;
            dp[i][0]+=f0[1];
            dp[i][1]+=f2[now];
            dp[i][2]+=f2[now^1];
        }
        else{
            f2[now]++;
            dp[i][0]+=f0[1];
            dp[i][1]+=f2[now^1];
            dp[i][2]+=f2[now];
            now^=1;
        }
        //printf("i:%d %lld %lld %lld\n",i,dp[i][1],dp[i][0],dp[i][2]);
    }

    while(m--){
        int ty;
        scanf("%d",&ty);
        if(ty==2){
            printf("%lld %lld %lld\n",dp[n][1],dp[n][0],dp[n][2]);
        }
        else{
            int t;
            scanf("%d",&t);
            while(t--){
                int x;
                scanf("%d",&x);
                for(int j=0;j<=2;++j) dp[n+1][j]=dp[n][j];
                //for(int j=0;j<3;++j) dp[i][j]=dp[i-1][j];
                f0[0]++;
                if(x==0){
                    f2[0]=0,f2[1]=0;
                    dp[n+1][0]+=n+1;
                    f0[1]=n+1;
                }
                else if(x>0){
                    f2[now]++;
                    dp[n+1][0]+=f0[1];
                    dp[n+1][1]+=f2[now];
                    dp[n+1][2]+=f2[now^1];
                }
                else{
                    f2[now]++;
                    dp[n+1][0]+=f0[1];
                    dp[n+1][1]+=f2[now^1];
                    dp[n+1][2]+=f2[now];
                    now^=1;
                }
                ++n;
            }
        }
    }
}
/*
9 2
-1 1 0 -1 1 0 -1 1 0
2
*/

I-植物大战僵尸

做法:二分一下最高能的值,check一下即可。

这题我代码爆longlong了,所以没有满分,气死人

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
ll n,m;
ll a[N];
int cal(ll mid)
{
    ll to=0;
    ll res=0;
    for(int i=1;i<n;++i){
        ++to;
        ++res;
        ll t=0;
        if(mid>to*a[i]){
            t=(mid-to*a[i])/a[i];
            if((mid-to*a[i])%a[i]) ++t;
        }
        res+=t*2;
        to=t;
    }
    if(mid>to*a[n]){
        ll t=(mid-to*a[n])/a[n];
        if((mid-to*a[n])%a[n]) ++t;
        --t;
        res++;
        res+=t*2;
    }
    //printf("mid:%lld res:%lld\n",mid,res);
    return res<=m;
}

int main()
{
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    cin>>n>>m;
    ll mi=(1ll<<62),mx=0;
    for(int i=1;i<=n;++i){
        scanf("%lld",&a[i]);
        mi=min(mi,a[i]);
    }

    if(m<=n){
        if(m==n) printf("%lld\n",mi);
        else printf("0");
        return 0;
    }
    ll l=0,r=1e12,ans=0;
    //puts("****");
    while(l<=r)
    {
        ll mid=l+r>>1;
        if(cal(mid)) {
            //printf("mid:%lld\n",mid);
            ans=mid,l=mid+1;
        }
        else r=mid-1;
    }
    printf("%lld\n",ans);
}

J-魔法青蛙

简单dp,dp[i]为前i个的最大值,容易想到两层for循环转移方程:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N],b[N],n,m;
ll dp[N];
int main()
{
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    cin>>n>>m;
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    for(int i=1;i<=n;++i) scanf("%d",&b[i]);
    ll ans=0;
    for(int i=1;i<=n;++i){
        dp[i]=b[i];
        for(int j=1;j<i;++j){
            if(a[i]%2==a[j]%2) continue;
            if(a[j]+m<a[i]) continue;
            //printf("i:%d j:%d\n",i,j);
            dp[i]=max(dp[i],dp[j]+b[i]);
        }
        ans=max(ans,dp[i]);
        //printf("i:%d:%lld\n",i,dp[i]);
    }
    printf("%lld\n",ans);
}

考虑把第二层for循环用线段树维护一下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int a[N],b[N],n,m,M;
ll dp[N];
ll mx[2][4*N];
void up(int id,int l,int r,int pos,ll val,int ty)
{
    if(l==r){
        mx[ty][id]=max(mx[ty][id],val);
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) up(id<<1,l,mid,pos,val,ty);
    else up(id<<1|1,mid+1,r,pos,val,ty);
    mx[ty][id]=max(mx[ty][id<<1],mx[ty][id<<1|1]);
}
ll qu(int id,int l,int r,int ql,int qr,int ty)
{
    if(ql<=l&&r<=qr){
        return mx[ty][id];
    }
    ll res=0;
    int mid=l+r>>1;
    //printf("id:%d l:%d r:%d\n",id,l,r);
    if(ql<=mid) res=qu(id<<1,l,mid,ql,qr,ty);
    if(qr>mid) res=max(res,qu(id<<1|1,mid+1,r,ql,qr,ty));
    return res;
}
int main()
{
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    M=2e5+10;
    cin>>n>>m;
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    for(int i=1;i<=n;++i) scanf("%d",&b[i]);
    ll ans=0;
    for(int i=1;i<=n;++i){
        if(a[i]%2){

            ll mx=qu(1,1,M,max(1,a[i]-m),M,0);

            dp[i]=mx+b[i];
            up(1,1,M,a[i],dp[i],1);
        }
        else{
            ll mx=qu(1,1,M,max(1,a[i]-m),M,1);
            dp[i]=mx+b[i];
            up(1,1,M,a[i],dp[i],0);
        }
        ans=max(ans,dp[i]);
        //printf("i:%d dp:%lld\n",i,dp[i]);
    }
    printf("%lld\n",ans);
}
发布了498 篇原创文章 · 获赞 66 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/104584484