蓝桥杯4道例题(4)

1.航班时间
来源:第九届蓝桥杯省赛C++A组
题目链接
在这里插入图片描述
题解:因为时差的原因,来回的两地的时间差是不相同的,存在一个时间大于另一个时间,因为里向西飞要减时差,向东飞要加时差,这样用大的时间差减小的时间差就能得到2倍的时差,也就能得到飞行时间

c++代码

#include<iostream>

using namespace std;

int getse(int h,int m,int s){
    
    return h*3600+m*60+s;}
int gettime()
{
    
    
    string line;
    getline(cin,line);

    if(line.back()!=')')line+="(+0)";//判断末尾是否有异日情况 无则加上(+0)方便格式化算时间
    int h1,h2,m1,m2,s1,s2,d;
    sscanf(line.c_str(),"%d:%d:%d %d:%d:%d (+%d)",&h1,&m1,&s1,&h2,&m2,&s2,&d);//c_str 放入string字符串 实际是string 到const char* 同时我们读入起降两个时间 和 day
    return getse(h2,m2,s2)-getse(h1,m1,s1)+d*3600*24;
}
int main()
{
    
    
    int n;
    cin>>n;

    getchar();//吞掉int 与 string 中间的回车

    while(n--)
        {
    
    
            int time =(gettime()+gettime())/2;
            printf("%02d:%02d:%02d\n",time/3600,time%3600/60,time%60);//02d没有两位则用0补足
        }
    return 0;
}


java代码:

public class Main {
    
    

static BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));
private static int get_second(int h,int m,int s)
{
    
    
    return 3600*h+m*60+s;
}
private static int get_time() throws IOException
{
    
    
    String str=buf.readLine();
    int day=0;
    if(str.charAt(str.length()-1)==')')
    {
    
    
        day=Integer.parseInt(""+str.charAt(str.length()-2));
        str=str.substring(0, str.length()-5);
    }
    String s[]=str.split(" ");
    String s1[]=s[0].split(":");
    String s2[]=s[1].split(":");
    int a1=Integer.parseInt(s1[0]);
    int a2=Integer.parseInt(s1[1]);
    int a3=Integer.parseInt(s1[2]);
    int b1=Integer.parseInt(s2[0]);
    int b2=Integer.parseInt(s2[1]);
    int b3=Integer.parseInt(s2[2]);
    return  get_second(b1, b2, b3)-get_second(a1, a2, a3)+day*24*3600;
}
public static void main(String args[]) throws IOException
{
    
    
    int n=Integer.parseInt(buf.readLine());
    while(n--!=0)
    {
    
    
        int time=(get_time()+get_time())/2;
        int hour=time/3600;
        int minute=time%3600/60;
        int secound=time%60;
        System.out.printf("%02d:%02d:%02d", hour,minute,secound);
        System.out.println();
    }
}
}


2.特别数的和
来源:第十届蓝桥杯省赛C++B组
题目链接
在这里插入图片描述
题解:既然要判断是否存在2019中的数,我们就把范围类所有数都枚举一遍,并且单独找出他们每个位上的数判断是否满足条件就可以了;

#include <iostream>

using namespace std;

int main(){
    
    
    int n;
    cin >> n;

    int ans = 0;
    for(int i = 1; i <= n; i ++){
    
    
        int x = i;
        while(x){
    
    
            int t = x % 10;//取出x的每一位
            x /= 10;
            if(t == 2 || t == 0 || t == 1 || t == 9){
    
    
                res += i;
                break;
            }
        }
    }

    cout << ans << endl;

   
}


java:

import java.util.Scanner;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int sum = 0;
        for(int i = 1; i <= n ;i++) {
    
    
            if(check(i)) {
    
    
                sum+=i;
            }
        }
        System.out.println(sum);
    }

    private static boolean check(int i) {
    
    
        while(i!=0) {
    
    
            if(i%10==2||i%10==9||i%10==1||i%10==0) {
    
    
                return true;
            }
            i/=10;
        }
        return false;
    }
}


3.k倍区间
来源:第八届蓝桥杯省赛C++B组
题目链接
在这里插入图片描述
题解:这题大致思路用的应该是前n项和

   cin>>a[1];
    long x;
    for(int i=2;i<=n;i++)
    {
    
    
        cin>>x;
        a[i]=x+a[i-1];
    }
    long ans=0;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            {
    
    

                if((a[j]-a[i])%k==0)
                ans++;
            }

核心代码如上,但其复杂度是n!,所以肯定超了,我们就要想想怎么优化,(a[j]-a[i])%k可以等价于a[j]%k-a[i]%k=0,也就是2个前n项和相等,我们就可以用这个进行优化,具体细节代码里讲解;
c++代码:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
const int N=100000+10;
long a[N];
int res[N];
int main()
{
    
       int n,k;
    cin>>n>>k;
    cin>>a[1];
    long x;
    for(int i=2;i<=n;i++)
    {
    
    
        cin>>x;
        a[i]=x+a[i-1];//计算前缀和
    }
    long ans=0;
    
    for(int i=1;i<=n;i++)
    {
    
    
        int v=a[i]%k;
        ans+=res[v];//用res存余数为v的个数,res[v]就表示在i之前有res[v]个余数为v的项,i和这些都可以组成一个k倍区间
        res[v]++;//加上现在这个余数为v的项
    }
        
    cout<<ans+res[0]<<endl;//为什么要加一个res[0],因为上面统计是通过2个区间相减满足k倍区间的数量,但对于余数为0的前n项和,其本身就是个k倍区间不需要和其他区间相减
}

java代码:

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    
    


    public static void main(String[] args) {
    
    
        Scanner sc=new Scanner(System.in);
        int n,k;
        n=sc.nextInt();
        k=sc.nextInt();
        final  int N=100000+30;
        long a[]=new long[N];
        a[1]=sc.nextInt();
        long x;
        long res[]=new long[N];
        Arrays.fill(res,0);
        for(int i=2;i<=n;i++) {
    
    
            x=sc.nextLong();
            a[i]=x+a[i-1];//计算前缀和

        }
        long ans=0;
        for(int i=1;i<=n;i++)
        {
    
    
            int v=(int)(a[i]%k);
            ans+=res[v];//用res存余数为v的个数,res[v]就表示在i之前有res[v]个余数为v的项,i和这些都可以组成一个k倍区间
            res[v]++;//加上现在这个余数为v的项
        }
        System.out.println(ans+res[0]);//为什么要加一个res[0],因为上面统计是通过2个区间相减满足k倍区间的数量,但对于余数为0的前n项和,其本身就是个k倍区间不需要和其他区间相减
    }
}

4.整数拼接
来源:第十一届蓝桥杯省赛C++B组
题目链接
在这里插入图片描述
题解:出处(https://www.acwing.com/solution/content/15969/)在这里插入图片描述
补充:从前往后跑一遍就是用现在这个数和在这个数前面的数组合,从后往前就是用这个数和这个数后面的数组合,以此做到不从不漏,并且不用判断是否为同一个数
c++代码:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

typedef unsigned long long ll;
const int N = 100010;

ll n, mod;      
ll ans;        
ll a[N];        
int cnt[11][N]; 

int log(int x) 
{
    
    
    int res = 0;
    while (x)
        x /= 10, res++;
    return res;
}

void get() 
{
    
    
    for (int i = 0; i < n; i++)
    {
    
    
        int v = (mod - a[i] % mod) % mod;//为什么补了%mod  如果前面的数小于mod 外面的mod没有影响,如果a[i]%mod=0 那么如果不补的话v就等于mod了,实际应该为0所以补一个%mod来消除这种特殊情况
        ans += cnt[log(a[i])][v];              
        for (ll j = 0, power = 1; j < 11; j++) 
        {
    
    
            cnt[j][power * a[i] % mod]++;
            power = power * 10;
        }
    }
}

int main()
{
    
    
    scanf("%d%d", &n, &mod);
    for (int i = 0; i < n; i++)
        scanf("%d", a + i);

    get();//从前往后
    memset(cnt, 0, sizeof cnt);
    reverse(a, a + n);

    get();//从后往前

    printf("%lld\n", ans);
    return 0;
}

java代码:

import java.util.Arrays;
import java.util.Scanner;
public class Main {
    
    
    final static int N=100110;
    static int [][]cnt=new int[11][N];
    static int n,mod;
    static long []a=new long [N];
    static long ans=0;

    public static void main(String[] args) {
    
    
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        mod=sc.nextInt();
        for(int i=1;i<=n;i++)
            a[i]=sc.nextLong();
        for(int i=1;i<11;i++)
        Arrays.fill(cnt[i],0);


        get();
        for(int i=1;i<11;i++)
            Arrays.fill(cnt[i],0);

        for(int begin=1,end=n;begin<end;begin++,end--)
        {
    
    
            long x=a[begin];
            a[begin]=a[end];
            a[end]=x;


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

    }
   static void get()
    {
    
    
        for (int i = 1; i <= n; i++)
        {
    
    
            int v =(int) (mod - a[i] % mod) % mod;//为什么补了%mod  如果前面的数小于mod 外面的mod没有影响,如果a[i]%mod=0 那么如果不补的话v就等于mod了,实际应该为0所以补一个%mod来消除这种特殊情况
            ans += cnt[log(a[i])][v];
            int power=1;
            for (int j = 0; j < 11; j++)
            {
    
    
                cnt[j][(int)(power * a[i] % mod)]++;
                power = power * 10%mod;
            }
        }

    }
   static int log(long x) // 返回 log10(x)
    {
    
    
        int res = 0;
        while (x>0) {
    
    
            x /= 10;
            res ++ ;
        }
        return res;
    }
}

猜你喜欢

转载自blog.csdn.net/jahup/article/details/107301980
今日推荐