第十三届蓝桥杯C/C++ B组答案+思路

测评(民间数据):http://oj.daimayuan.top/course/18/problems

A 九进制转十进制(100%)

在这里插入图片描述

思路:

类比2进制, 最低位(最右边)为20,第二位为21
同理此题答案为 2*90+2*91+0*92+2*93=1478

答案:

1478

B 顺子日期(100%)

在这里插入图片描述

思路:

(猜题意)连续的3个上升的是顺子(具体看题目20221023中的210),还有就是0算在里面
不愿意想就直接无脑的写个代码

答案:

14

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;

int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};

bool judge(int y,int m,int d){
    vector<int> v;
    v.push_back(2),v.push_back(0),v.push_back(2),v.push_back(2);
    if(m>=10) v.push_back(1);
    else v.push_back(0);
    v.push_back(m%10);

    if(d >= 10) v.push_back(d/10);
    else v.push_back(0);
    v.push_back(d%10);
    int now=1;
    for(int i=1;i<v.size();++i){
        if(v[i]==v[i-1]+1) now++;
        else now=1;
        if(now>=3) return true;
    }
    return false;
}
int main()
{
    int ans=0;
    for(int i=1;i<=12;++i){
        for(int j=1;j<=day[i];++j){
            if(judge(2022,i,j)) ans++;
        }
    }
    cout << ans << endl;
    return 0;
}

C 刷题统计(100%)

在这里插入图片描述
【样例输入1】

10 20 99

【样例输出1】

8

【评测用例规模与约定】

对于 50% 的评测用例,1 ≤ a, b, n ≤ 106
对于 100% 的评测用例,1 ≤ a, b, n ≤ 1018

.
思路:

首先算出一周能刷多少题 5*a+2*b
然后算多出来的花几天能刷完
5e18+2e18=7e18 < long long(9223372036854775807)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;

int main()
{
    ll a,b,n;//注意用long long
    cin >> a >> b >> n;
    ll ans=0;
    ll week=n/(5*a+2*b);
    ans+=week*7;
    n-=week*(5*a+2*b);
    for(int i=1;i<=5;++i){
        if(n<=0) break;
        n-=a;ans++;
    }
    if(n > b) ans+=2;
    else if(n > 0) ans+=1;
    cout << ans << endl;
    return 0;
}

D 修剪灌木(100%)

在这里插入图片描述
【样例输入】

3

【样例输出】

4
2
4

【评测用例规模与约定】

对于 30% 的数据,N ≤ 10.
对于 100% 的数据,1 < N ≤ 10000.

思路:

刚开始全是0,每天傍晚前长高1,傍晚后爱丽丝来修剪,也就是说爱丽丝剪完第 i 个灌木后可能会去 i 的左边,也可能去 i 的右边,然后返回来,所以他长的最长高度就是左右两边数目中的取更大的*2 就是答案了
在比赛的时候看着好像是左右对称且每个是前面一个减2(但是要注意1的特判)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;

int A[N];
int main()
{
    int n;
    cin >> n;
    if(n==1){cout << 1 << endl;return 0;}
    A[1]=A[n]=(n-1)*2;
    for(int i=2;i<=n;++i){
        if(A[i]!=0) break;
        A[i]=A[n-i+1]=A[i-1]-2;
    }
    for(int i=1;i<=n;++i){
        cout << A[i] << endl;
    }
    return 0;
}

E X进制减法(100%)

在这里插入图片描述
【样例输入】

11
3
10 4 0
3
1 2 0

【样例输出】

94

【样例说明】

当进制为:最低位 2 进制,第二数位 5 进制,第三数位 11 进制时
减法得到的差最小。
此时 A 在十进制下是 108,B 在十进制下是 14,差值是 94

【评测用例规模与约定】

对于 30% 的数据,N ≤ 10; Ma, Mb ≤ 8.
对于 100% 的数据,2 ≤ N ≤ 1000; 1 ≤ Ma, Mb ≤ 100000; A ≥ B.

思路:

首先很多同学不懂 321 怎么转换成的 65
我们正着推不好推那就反着推看看65—>321
最低位的进制是2进制,也就是满2进1所以65/2=32余1(进32余1)
然后第二位为10进制,满10进1 所以32/10=3余2(进3余2)
最后以为为8进制 进上来3直接填上就好了
.
所以可以倒推出321->65 即每一位乘上一位的进制
即(3*10+2)*2+1=65
.
最后题目给出A>=b,所以不用考虑负数的情况
猜结论)
如果进制尽可能地小,则差值更小(为什么呢)贪心猜测:如果到第k位前k-1位都是按照同样的进制运算的A为ansA,B为ansB,且相应A,B此位为a1,b1。则此处的A运算为ansA*k+a1,B运算为ansB*k+b1 且已知ansA >=ansB 则k越小差值越小。
不知道对不对 而且比赛的时候忘记可能会存在前导零了QAQ

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;
const int mod=1e9+7;
int k[N];

int main()
{
    int N,Ma,Mb;
    cin >> N;
    cin >> Ma;
    vector<int> A(Ma);
    for(int i=0;i<Ma;++i){
        cin >> A[i];
    }
    cin >> Mb;
    vector<int> B(Mb);
    for(int i=0;i<Mb;++i){
        cin >> B[i];
    }
    //对齐
    reverse(B.begin(),B.end());
    reverse(A.begin(),A.end());
    while(A.size()!=B.size()){
        if(A.size() < B.size()) A.push_back(0);
        else B.push_back(0);
    }
    reverse(B.begin(),B.end());
    reverse(A.begin(),A.end());
    int n=A.size();

    ll ans1=0,ans2=0;
    for(int i=0;i<n;++i){
        int now=max(A[i],B[i]);
        if(now==0) k[i]=2;
        else k[i]=now+1;
    }
    k[n]=1;
    for(int i=0;i<n;++i){
        ans1=(ans1+A[i])*k[i+1]%mod;
    }
    for(int i=0;i<n;++i){
        ans2=(ans2+B[i])*k[i+1]%mod;
    }
    cout << (ans1-ans2+mod)%mod;
    return 0;
}

F 统计子矩阵(70%)

在这里插入图片描述

【样例输入】

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

【样例输出】

19

【样例说明】

满足条件的子矩阵一共有 19,包含:
大小为 1 × 1 的有 10 个。
大小为 1 × 2 的有 3 个。
大小为 1 × 3 的有 2 个。
大小为 1 × 4 的有 1 个。
大小为 2 × 1 的有 3 个。

【评测用例规模与约定】
对于 30% 的数据,N, M ≤ 20.
对于 70% 的数据,N, M ≤ 100.
对于 100% 的数据,1 ≤ N, M ≤ 500; 0 ≤ Ai j ≤ 1000; 1 ≤ K ≤ 250000000.
思路:

QAQ只会前缀和然后暴力骗分
首先要用二维前缀和
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+A[i][j];
然后遍历每个点往左上角看有多少个子矩阵满足条件
(只能骗70%的分)

批注:最多只能过前70%的样例,如果有更好的方法欢迎在评论区留言

答案:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e3+10;

int A[N][N];
int sum[N][N];

int getsum(int i,int j,int k,int l){
    return sum[i][j]-sum[i][l-1]-sum[k-1][j]+sum[k-1][l-1];
}

int main()
{
    int n,m,K;
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            scanf("%d",&A[i][j]);
        }
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+A[i][j];
        }
    }
    int ans=0;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            for(int k=1;k<=i;++k){
                for(int l=1;l<=j;++l){
                    if(getsum(i,j,k,l) <= K) ans++;
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

G 积木画(100%)

在这里插入图片描述

【样例输入】

3

【样例输出】

5

在这里插入图片描述

【评测用例规模与约定】
对于所有测试用例,1 ≤ N ≤ 10000000.

思路(考场思路):

  • dp
    考场上的思路:

在这里插入图片描述

答案:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e7+10;
const int mod=1e9+7;
int dp[N][4];

int main()
{
    int n;
    cin >> n;
    dp[0][1]=1;
    for(int i=1;i<=n;++i){
        dp[i][1]=(dp[i][1]+dp[i-1][1])%mod;
        dp[i][1]=(dp[i][1]+dp[i-1][2])%mod;
        dp[i][1]=(dp[i][1]+dp[i-1][3])%mod;
        if(i >= 2) dp[i][1]=(dp[i][1]+dp[i-2][1])%mod;
        
        dp[i][2]=(dp[i-1][3])%mod;
        if(i >= 2) dp[i][2]=(dp[i][2]+dp[i-2][1])%mod;

        dp[i][3]=(dp[i-1][2])%mod;
        if(i >= 2) dp[i][3]=(dp[i][3]+dp[i-2][1])%mod;
    }
    cout << dp[n][1];
    return 0;
}

H 扫雷(0%)

在这里插入图片描述

【样例输入】

2 1
2 2 4
4 4 2
0 0 5

【样例输出】

2

在这里插入图片描述

【评测用例规模与约定】
对于 40% 的评测用例:0 ≤ x, y ≤ 109, 0 ≤ n, m ≤ 103, 1 ≤ r ≤ 10.
对于 100% 的评测用例:0 ≤ x, y ≤ 109, 0 ≤ n, m ≤ 5 × 104, 1 ≤ r ≤ 10

批注:不会,1分都没骗。。

I 李白打酒加强版(100%)

在这里插入图片描述

【样例输入】

5 10

【样例输出】

14

【样例说明】
如果我们用 0 代表遇到花,1 代表遇到店,14 种顺序如下:
010101101000000
010110010010000
011000110010000
100010110010000
011001000110000
100011000110000
100100010110000
010110100000100
011001001000100
100011001000100
100100011000100
011010000010100
100100100010100
101000001010100
【评测用例规模与约定】
对于 40% 的评测用例:1 ≤ N, M ≤ 10。
对于 100% 的评测用例:1 ≤ N, M ≤ 100。

思路:

(好像是dp)不过我选择骗分!!40%的1 ≤ N, M ≤ 10。 直接全排列看那个符合条件(220不大)

批注:最多只能过前40%的样例,如果有更好的方法欢迎在评论区留言

答案:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;

vector<int> v;
int ans=0;
void dfs(int nown,int nowm){
    if(nown==0 && nowm==0){
        int now=2;
        v.push_back(0);
        for(int i=0;i<v.size();++i){
            if(v[i]==1) now*=2;
            else now-=1;
            if(now < 0){
                v.pop_back();
                return;
            }
        }
        if(now==0) 
            ans++;
        v.pop_back();
        return;
    }
    if(nown > 0){
        v.push_back(1);
        dfs(nown-1,nowm);
        v.pop_back();
    }
    if(nowm > 0){
        v.push_back(0);
        dfs(nown,nowm-1);
        v.pop_back();
    }
}

int main()
{
    int n,m;
    cin >> n>> m;
    dfs(n,m-1);//最后一个必为花
    cout << ans << endl;
    return 0;
}

赛后补题记忆化dfs

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=2e2+10;
const int mod=1e9+7;
ll dp[N][N][N];//到第x个位置,花剩多少个可以用,到这里的价值是多少,的方案数
int n,m;//n个店 m个花

int dfs(int x,int nowm,int v){
    if(v >= n+m) return 0;
    if(dp[x][nowm][v]!=-1) return dp[x][nowm][v]%mod;
    int res=0;
    if(nowm>0)  res=(res+dfs(x+1,nowm-1,v-1))%mod;
    res=(res+dfs(x+1,nowm,2*v))%mod;
    return dp[x][nowm][v]=res%mod;
}

int main()
{
    cin >> n >> m;
    for(int i=1;i<=n+m-1;++i){
        for(int j=1;j<=m;++j){
            for(int k=1;k<=n+m;++k){
                dp[i][j][k]=-1;
            }
        }
    }
    dp[n+m][0][1]=1;//如果到第n+m个位置,手中的花剩下0个,且剩下1斗酒,就可行
    cout << dfs(1,m-1,2);

    return 0;
}

队友gzj的dp:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=2e2+10;
const int mod=1e9+7;
ll dp[N][N][N];//到第x个位置,花剩多少个可以用,到这里的价值是多少,的方案数
int n,m;//n个店 m个花

int main()
{
    cin >> n >> m;
    dp[0][m][2]=1;
    for(int i=1;i<=n+m;i++){
        for(int j=0;j<=m;j++){
            for(int k=205;k>=0;k--){
                dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+1][k+1])%mod;
                if(k%2==0)
                    dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k/2])%mod;
            }
        }
    }
    cout<<dp[n+m-1][1][1]%mod<<endl;

    return 0;
}

J 砍竹子(100%)

在这里插入图片描述

【样例输入】

6
2 1 4 2 6 7

【样例输出】

5

【样例说明】
其中一种方案:
2 1 4 2 6 7
→ 2 1 4 2 6 2
→ 2 1 4 2 2 2
→ 2 1 1 2 2 2
→ 1 1 1 2 2 2
→ 1 1 1 1 1 1
共需要 5 步完成
【评测用例规模与约定】
对于 20% 的数据,保证 n ≤ 1000, hi ≤ 106
对于 100% 的数据,保证 n ≤ 2 × 105, hi ≤ 1018
思路:

(比赛的时候没写)看题目的公式1e18化为1也就不到10次,所以不用担心hi太大时间复杂度太高
用优先队列进行处理,将首先从大到小砍(说不定砍成的数和某个小的刚好挨着可以一起砍掉)
怎么说,,,思路感觉也不是很难,看代码吧不知道对不对

#include<bits/stdc++.h>
#include<time.h>
using namespace std;
#define ll long long
#define int128 __int128
#define random1(x,y) (rand()%(1ll*y-1ll*x+1ll)+1ll*x)
typedef pair<int,int> PII;
const int N=1e6+10;

struct node{
    ll x,id;
    bool operator < (const node& b)const{
        if(x==b.x) return id < b.id;
        else return x < b.x;
    }
};
int getnum(ll a){
    return (int)(sqrt(a/2+1));
}
priority_queue<node> q;
ll A[N];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        ll temp;
        scanf("%lld",&temp);
        q.push({temp,i});
    }
    /*
    //把上面的删掉
    srand( (unsigned)time( NULL ) );//这里
    int n=200000;
    for(int i=0;i<n;++i){
        q.push({random1(1,10000000000000000),i});
    }
	clock_t stime = clock(); //开始计时
    */
    ll ans=0;
    while(q.top().x!=1){
        node now=q.top();
        q.pop();
        int nowid=now.id;
        ll nowx=now.x;
        ans++;
        q.push({getnum(now.x),nowid});
        while(q.top().x==nowx){
            node temp=q.top();
            q.pop();
            if(temp.id!=nowid-1){
                ans++;
            }
            nowid=temp.id;
            q.push({getnum(now.x),nowid});
        }
    }
    cout << ans << endl;
    // clock_t etime = clock(); //结束计时
	// printf("running time is :%d ms\n", etime-stime);
    return 0;
}

批注:如果有误或者某题有更好的思路,欢迎在评论区留言^_^

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值