蓝桥杯4道例题

难度由小到大

1.翻硬币
来源:第四届蓝桥杯省赛C++B组
题目链接
在这里插入图片描述
题解:
题目中说我们翻动硬币时,必须翻动连续的2个,也就是说如果我们要翻6号硬币 要么一起翻5号和6好,要么一起翻6号和7号,那么我们可以将这2种情况分开考虑,每次我们翻动一个硬币,就必须翻动它后面的那个硬币,虽然对翻动的方法进行了限定,但情况是不比翻动前面的硬币或后面的硬币少的,就好比上面的例子,我们要翻动,56硬币,那么我们翻动5就好,翻动67,那么我们翻动6就好,情况是没有少的;

c++代码

#include<iostream>
using namespace std;
string a,b;
int ans;
int main(){
    cin>>a>>b;
    for(int i=0;i<a.length();i++){
        if(b[i]==a[i]){ //如果目标状态和输入状态相同,跳过即可
            continue;
        }
        else{
            for(int j=i;j<=i+1;j++){ //更新当前硬币状态和下一个硬币状态
                    //这也是为什么选择翻后面硬币的原因,因为前面的硬币已经符合答案要求了。翻了只会增加翻动次数
                if(a[j]=='o') a[j]='*';
                else a[j]='o';
            }

            ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}



java代码:

import java.util.Scanner;

public class Main {


    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int ans=0;



        StringBuilder a=new StringBuilder(sc.next());
        StringBuilder b=new StringBuilder(sc.next());



        for(int i=0;i<a.length();i++){
            if(b.charAt(i)==a.charAt(i)){ //如果目标状态和输入状态相同,跳过即可
                continue;
            }
            else{
                for(int j=i;j<=i+1&&j<a.length();j++){ //更新当前硬币状态和下一个硬币状态
                    //这也是为什么选择翻后面硬币的原因,因为前面的硬币已经符合答案要求了。翻了只会增加翻动次数
                    if(a.charAt(j)=='o') a.setCharAt(j,'*');
                    else if (a.charAt(j)=='*') a.setCharAt(j,'o');
                }

                ans++;
            }
        }
        System.out.println(ans);
    }






}

2.四平方合
来源:第七届蓝桥杯省赛C++A/B组
题目链接
在这里插入图片描述
题解:此题因为我菜,c++的hash_map给忘了,所以这里我c++和java提供2总不同的方法;
c++代码:

#include<iostream>
#include<algorithm>

using namespace std;

const int N=5e6+10;
int n,cnt;

struct node{
    int v,c,d;
    bool operator < (const node &t)const    //重载< 因为sort给结构体排序,括号中的const表示参数a对象不会被修改,最后的const表明调用函数对象不会被修改
    {
        if(v!=t.v)return v<t.v;
        if(c!=t.c)return c<t.c;
        if(d!=t.d)return d<t.d;//优先按v排序
    }
}node[N];
int main()
{
    cin>>n;
    for(int c=0;c*c<=n;c++)
        for(int d=c;d*d+c*c<=n;d++)//枚举一遍
            node[cnt++]={c*c+d*d,c,d};

    sort(node,node+cnt);

    for(int a=0;a*a<=n;a++)
        for(int b=a;a*a+b*b<=n;b++)
            {
                int l=0,r=cnt-1;
                int t=n-a*a-b*b;
                while(l<r)// a<b,c<d,ab之后二分查找cd的值,所以一定是最小升序
                    {
                        int mid=l+r>>1;
                        if(node[mid].v>=t)r=mid;
                        else l=mid+1;
                    }
                if(node[l].v==t)
                    {
                        cout<<a<<" "<<b<<" "<<node[l].c<<" "<<node[l].d;
                        return 0;
                    }
            }
}

java代码:
其实就是利用哈希表把二分给优化掉了

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    static Map<Integer,Integer> map = new HashMap<Integer,Integer>();
    public static void solve(int n)
    {
        //1、预处理,使用哈希表记录c*c + d*d的值
        for(int i = 0;i * i * 2 <= n;i++)
            for(int j = i;i * i + j * j <= n;j ++)
                if(!map.containsKey(i * i + j * j))
                    map.put(i * i + j * j, i);
        //2、枚举a,b
        for(int i = 0;i * i * 4 <= n;i++)
            for(int j = i;(i * i + j * j) * 2 <= n;j++)
            {
                //若c^2 + d^2 = n - a^2 - b^2;
                if(map.containsKey(n - i * i - j * j))
                {
                    int c = map.get(n - i * i - j * j);
                    int d = (int) Math.sqrt(n - i * i - j * j - c * c);
                    System.out.println(i + " " + j + " " + c + " " + d + " ");
                    return;
                }
            }
    }
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        solve(n);
    }
}


3.大臣的旅费
来源:第四届蓝桥杯省赛C++A组
题目链接
在这里插入图片描述
题解:树形dp题,我们选择任意一点为根节点进行DFS,将他到其他点的最长距离和次长距离记录下来,从该点出发到其他点的最长距离 + 次长距离就是我们要求的树的最长距离。

#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std;


const int N=1e5+10;
vector<int>ver[N],edge[N];
long long ans;
bool st[N];
int dfs(int u)
{
    int res = 0;
    int max2 = 0;

    st[u] = true;

    for(int i=0;i<ver[u].size();i++)
    {
        int p = ver[u][i] , d = edge[u][i];
        if(st[p]) continue;
        int v = dfs(p) + d;
        if(v > res) max2 = res , res = v;
        else if(v > max2) max2 = v;

    }

    ans = max(ans,0ll + max2 + res);

    return res;
}



int main()
{

    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {   int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        ver[a].push_back(b);
        edge[a].push_back(c);
        ver[b].push_back(a);
        edge[b].push_back(c);
    }

    dfs(1);

    printf("%lld\n",10 * ans + (ans + 1) * ans / 2);

    return 0;

}

java代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int N = 100010;
    static int M = N * 2;
    static int[] h = new int[N];
    static int[] e = new int[M];
    static int[] ne = new int[M];
    static int[] w = new int[M];
    static int idx = 0;
    static int ans = 0;
    static void add(int a,int b,int c)
    {
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx ++;
    }
    //找到u点往下走的最大长度
    static int dfs(int u,int father)
    {
        int d1 = 0;//最大值
        int d2 = 0;//次大值
        for(int i = h[u];i != -1;i = ne[i])
        {
            int j = e[i];
            if(j == father) continue;
            int d = dfs(j,u) + w[i];

            if(d > d1) {d2 = d1; d1 = d;}
            else if(d > d2) {d2 = d;}
        }
        ans = Math.max(ans, d1 + d2);
        return d1;
    }
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(reader.readLine().trim());
        Arrays.fill(h,-1);
        for(int i = 0;i < n - 1;i ++)
        {
            String[] s1 = reader.readLine().split(" ");
            int a = Integer.parseInt(s1[0]);
            int b = Integer.parseInt(s1[1]);
            int c = Integer.parseInt(s1[2]);
            add(a,b,c);
            add(b,a,c);
        }
        dfs(1,-1);
        System.out.println(ans * 10 + ((long)(ans + 1) * ans ) / 2);
    }
}


4.小朋友排队
来源:第五届蓝桥杯省赛C++B组
题目链接
在这里插入图片描述
这个题实际上是逆序对的个数(因为是按从小到大排列,逆序对的个数为基数(逆序对是相对于一个数而言的)前面大于基数的数的个数加上基数后方小于基数的数的个数),这个相信学过线性代数的朋友不难理解,但如果直接暴力求的话会超时,所以我们这里用树状数组来做,现在也就差不多变成了个线代数组的模板题,维护的是数的个数
树状数组讲解
c++代码

#include<iostream>
#include<string.h>

using namespace std;
typedef long long ll;
const int N=1000000 +10;
int n;
ll a[N],tr[N],b[N];

int lowbit(int x){
return x&-x;

}


void add(int x)
{
    for(int i=x;i<N;i+=lowbit(i))  tr[i]++;//统计小于x数的个数

}

int query(int x){

int ans=0;
for(int i=x;i;i-=lowbit(i))
    ans+=tr[i];

    return ans;



}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        {cin>>a[i];
          a[i]++;
        }

        for(int i=1;i<=n;i++){
            add(a[i]);
            b[i]=i-query(a[i]);//这个数前面比他大的数的个数就是 总的数的个数减去比它小的数的个数

        }
        memset(tr,0,sizeof tr);
        for(int i=n;i>=1;i--){
        add(a[i]);
        b[i]+=query(a[i]-1);  //比这个数小
    }
    long long res=0;

    for(int i=1;i<=n;i++){
        res+=(1+b[i])*b[i]/2;
    }//等差求和
    cout<<res<<endl;


}

java

import java.util.HashMap;
import java.util.Scanner;

public class main {

      public static final int N=1000000+10;
     static long a[]=new long [N];
     static long b[]=new long [N];
      static long tr[]=new long [N];

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n;
        n=sc.nextInt();

        for(int i=1;i<=n;i++)
        {a[i]=sc.nextInt();
            a[i]++;
        }

        for(int i=1;i<=n;i++){
            add(a[i]);
            b[i]=i-query(a[i]);//这个数前面比他大的数的个数就是 总的数的个数减去比它小的数的个数

        }
        tr=new long[N];
        for(int i=n;i>=1;i--){
            add(a[i]);
            b[i]+=query(a[i]-1);  //比这个数小
        }
        long res=0;

        for(int i=1;i<=n;i++){
            res+=(1+b[i])*b[i]/2;
        }//等差求和
        System.out.println(res);





    }

   static long lowbit(long x){
        return x&-x;

    }


   static void add(long x)
    {
        for(long i=x;i<N;i+=lowbit(i))  tr[(int)i]++;//统计小于x数的个数

    }

   static int query(long x){

        int ans=0;
        for(long i=x;i>0;i-=lowbit(i))
            ans+=tr[(int)i];

        return ans;



    }



}
  • 17
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值