【C++ / Java】蓝桥杯 —— 算法训练(一)

  • 蓝桥杯1012 算法训练 区间k大数查询(水题)
  • 蓝桥杯1099 算法训练 传纸条(动态规划)
  • 蓝桥杯1100 算法训练 Hankson的趣味题(数论)
  • 蓝桥杯1101 算法训练 接水问题(模拟)
  • 蓝桥杯1105 算法训练 调和数列问题(水题)
  • 蓝桥杯1106 算法训练 Hanoi问题(递归)
  • 蓝桥杯1107 算法训练 蜜蜂飞舞(水题)
  • 蓝桥杯1110 算法训练 数组查找及替换(模拟)
  • 蓝桥杯1132 算法训练 比赛安排(模拟)
  • 蓝桥杯1133 算法训练 字符串编辑(模拟)


蓝桥杯1012 算法训练 区间k大数查询(水题)

原题链接: 算法训练 区间k大数查询

  • 思路: 数据挺小的吧,暴力即可。对于m次询问,用一个数组 b[i] 暂存数组a[l] ~ a[r] 的值,然后从大到小排下序,输出该区间第 k 个数。

  • 注意: 每次询问先将数组 b[i] 初始化为0 !!!

C++ Code:

#include 
#include 
#include 
using namespace std;
int a[100100];
int b[100100];
bool cmp(int a,int b){
    return a>b;
}
int main(){
    int n;  cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    int m;  cin>>m;
    while(m--){
        memset(b,0,sizeof(b));
        int l,r,k;
        cin>>l>>r>>k;
        for(int i=l;i<=r;i++)
            b[i]=a[i];
        sort(b+l,b+r+1,cmp);
        cout<<b[l+k-1]<<endl;
    }
}

Java Code:

import java.util.Arrays;
import java.util.Scanner;
public class Main {
	static int[] a = new int[10010];
	static int[] b = new int[10010];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		for(int i=1;i<=n;i++)
			a[i] = cin.nextInt();
		int m = cin.nextInt();
		while(m-- >0) {
			int l = cin.nextInt();
			int r = cin.nextInt();
			int k = cin.nextInt();
			for(int i=l;i<=r;i++)
				b[i]=a[i];
			Arrays.sort(b,l,r+1);
			System.out.println(b[r-k+1]);
		}
	}
}


蓝桥杯1099 算法训练 传纸条(动态规划)

原题链接:算法训练 传纸条

  • 思路: 有点水,暴力dp也能过。用两个for来枚举第一次走的横纵坐标,另外两个for来枚举第二次走的横纵坐标。
一共分四种情况:

1. dp[i][j][k][l] = dp[i-1][j][k-1][l]	//两次都是从上面走下来的

2. dp[i][j][k][l] = dp[i][j-1][k][l-1]	//两次都是从左边走过来的

3. dp[i][j][k][l] = dp[i-1][j][k][l-1]	//第一次从上面走来,第二次从左边走来

4. dp[i][j][k][l] = dp[i][j-1][k-1][l]	//第一次从左边走来,第二次从上面走来

状态转移方程:
dp[i][j][k][l]=max(max(dp[i-1][j][k-1][l],dp[i][j-1][k][l-1]),max(dp[i-1][j][k][l-1],dp[i][j-1][k-1][l]))+a[i][j]

同时还要判断两次走的路径是否相交:
if(i!=k&&j!=l) 	dp[i][j][k][l]+=a[k][l];

C++ Code:

#include 
#include 
using namespace std;
int a[55][55];
int dp[55][55][55][55];
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>a[i][j];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			for(int k=1;k<=n;k++){
				for(int l=1;l<=m;l++){
					int x=max(dp[i-1][j][k-1][l],dp[i][j-1][k][l-1]);
					int y=max(dp[i-1][j][k][l-1],dp[i][j-1][k-1][l]);
					dp[i][j][k][l]=max(x,y)+a[i][j];
					if(i!=k && j!=l)
						dp[i][j][k][l]+=a[k][l];
				}
			}
		}
	}
	cout<<dp[n][m][n][m]<<endl;
	return 0;
}

Java Code:

import java.util.Scanner;
public class Main {
	public static int[][] a = new int[55][55];
	public static int[][][][] dp = new int[55][55][55][55];
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		int m = cin.nextInt();
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				a[i][j] = cin.nextInt();
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				for(int k=1;k<=n;k++){
					for(int l=1;l<=m;l++){
						int x=Math.max(dp[i-1][j][k-1][l],dp[i][j-1][k][l-1]);
						int y=Math.max(dp[i-1][j][k][l-1],dp[i][j-1][k-1][l]);
						dp[i][j][k][l]=Math.max(x,y)+a[i][j];
						if(i!=k && j!=l)
							dp[i][j][k][l]+=a[k][l];
					}
				}
			}
		}
		System.out.println(dp[n][m][n][m]);
	}
}


蓝桥杯1100 算法训练 Hankson的趣味题(数论)

原题链接:算法训练 Hankson的趣味题

  • 题意: 求出满足条件的 x 的个数:gcd(x,a0) = a1,lcm(x,b0) = b1。

  • 思路: 这道题暴力枚举只能过部分的点。其实这是一道数论题。x 是 a1的整数倍且是 b1 的因子,所以可以枚举 b1 的因子,也就是 x,如果这个数是 a1 的整数倍,并且满足那两个式子,则 ans++。找到 x 的时候要注意是否存在 b1 的另一个因子 y 。

  • 重要结论: 对于两个正整数a,b,设 gcd(a, b)=k,则存在gcd(a/k, b/k)=1

具体证明过程见大佬博客:NOIP2009Hankson的趣味题


Code1: 暴力枚举法,不能全部 AC。

import java.util.Scanner;
public class Main {
	static long gcd(long a,long b) {
		return a%b==0?b:gcd(b,a%b);
	}
	static long lcm(long a,long b) {
		return a*b/gcd(a,b);
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int t = cin.nextInt();
		while(t-- >0) {
			long a0 = cin.nextLong();
			long a1 = cin.nextLong();
			long b0 = cin.nextLong();
			long b1 = cin.nextLong();
			int x=0,ans=0;
			for(int i=1;i<10000000;i++) {
				if(gcd(i,a0)==a1) {
					x=i;
					break;
				}
			}
			for(int i=x;i<=b1;i++) {
				if(lcm(i,b0)==b1)
					ans++;
			}
			System.out.println(ans);
		}
	}
}

Code2: 用 long 型只能过部分样例,事实证明不能随便用 long 型。

import java.util.Scanner;
public class Main {
	static int gcd(int a,int b) {
		return b==0?a:gcd(b,a%b);
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		int t = cin.nextInt();
		while(t-- >0) {
			int a0 = cin.nextInt();
			int a1 = cin.nextInt();
			int b0 = cin.nextInt();
			int b1 = cin.nextInt();
			int p = a0/a1, q = b1/b0, ans=0; 
			for(int x=1;x*x<=b1;x++) {
				if(b1%x==0) {
					if(x%a1==0 && gcd(x/a1,p)==1 && gcd(q,b1/x)==1)	ans++;
					int y = b1/x;
					if(x==y)	continue;
					if(y%a1==0 && gcd(y/a1,p)==1 && gcd(q,b1/y)==1)	ans++;
				}
			}
			System.out.println(ans);
		}
	}
}


蓝桥杯1101 算法训练 接水问题(模拟)

原题链接:算法训练 接水问题

  • 思路: 注意人的接水顺序不变。
    1. 如果 n<=m ,直接输出所有人当中接水时间最长的那个即可。
    2. 如果 n>=m,先把前m个人从小到大排序,第一个人打完水,则第m+1个人替换到第一个人的位置,直到剩下m个人,此时直到再加上m个人中最大接水时间输出即可。

C++ Code:

#include 
#include 
using namespace std;
int w[100000];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>w[i];
    int ans=0,t=m;  //ans表示所需时间,t表示替换到第t位同学
    if(n<=m){   //人数小于等于水龙头数直接输出最大的
        sort(w+1,w+1+n);
        cout<<w[n]<<endl;
    }else{
        while(w[m]){    //当第m个水龙头还有人
            sort(w+1,w+1+m);
            while(w[1]){    //只要第一个水龙头的人未装满就时间就一直增加
                for(int i=1;i<=m;i++)
                    w[i]--;
                ans++;
            }
            w[1]=w[t+1];    //更替下一位同学
            if(t+1==n){ //如果剩下m位同学直接输出剩下的所需时间最大的就可以了
                sort(w+1,w+1+m);
                ans+=w[m];
                cout<<ans<<endl;
                return 0;
            }
            t++;
        }
    }
}

Java Code:

import java.util.Arrays;
import java.util.Scanner;
public class Main {
	static int[] a = new int[10010];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		int m = cin.nextInt();
		for(int i=1;i<=n;i++)
			a[i] = cin.nextInt();
		if(n<=m) {
			Arrays.sort(a,1,n+1);
			System.out.println(a[n]);
		}
		else {
			int ans=0,t=m;
			while(a[m]>0) {
				Arrays.sort(a,1,m+1);
				while(a[1]>0) {
					for(int i=1;i<=m;i++)
						a[i]--;
					ans++;
				}
				a[1]=a[t+1];
				if(t+1==n) {
					Arrays.sort(a,1,m+1);
					ans+=a[m];
					System.out.println(ans);
					break;
				}
				t++;
			}
		}
	}
}


蓝桥杯1105 算法训练 调和数列问题(水题)

原题链接:算法训练 调和数列问题

  • 思路: 一道水题,直接遍历寻找答案,记得减掉1。

  • 注意: 不能用 1 / i ,而是 1.0 / i ,以及判断语句的位置要注意。

C++ Code:

#include 
using namespace std;
int main(){
    double x;
    while(cin>>x && x!=0.00){
        double ans=0.0;
        for(int i=2;;i++){
            ans+=(1.0/i);   //注意因为结果是浮点数,所以要用1.0来除
            if(ans>=x){     //判断语句要放在这里
                cout<<i-1<<" card(s)"<<endl;
                break;
            }
        }
    }
    return 0;
}

Java Code:

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		while(cin.hasNext()) {
			double x = cin.nextDouble();
			if(x==0.00)	break;
			int i;
			double ans=0.0;
			for(i=1;;i++) {
				ans+=1.0/(i+1);
				if(ans>=x)	break;
			}
			System.out.println(i+" card(s)");
		}
	}
}


蓝桥杯1106 算法训练 Hanoi问题(递归)

原题链接:算法训练 Hanoi问题

  • 思路: 汉诺塔问题的变形,但做法还是类似的。这道题有递归做法,也可以当成数学问题直接套用公式来做。

C++ Code1:

#include 
using namespace std;
int ans;
void hanoi(int n,int m,char a,char b,char c){
	if(n<=m)
		ans++;
	else{
		hanoi(n-m,m,a,c,b);
		ans++;
		hanoi(n-m,m,b,a,c);
	}
}
int main(){
	int n,m;
	cin>>n>>m;
	hanoi(n,m,'x','y','z');
	cout<<ans<<endl;
	return 0;
}

/*
一般汉诺塔问题代码:
#include 
using namespace std;
int ans;
void hanoi(int n,char a,char b,char c){
	if(n==1)
		ans++;
	else{
		hanoi(n-1,a,c,b);
		ans++;
		hanoi(n-1,b,a,c);
	}
}
int main(){
	int n,m;
	cin>>n;
	hanoi(n,'x','y','z');
	cout<

C++ Code2:

//递归得出公式 f(n) = 2f(n)+1, 然后通过数学推算得通项公式为 f(n) = 2^n-1
#include 
#include 
using namespace std;
int main(){
	int n,m;
	cin>>n>>m;
	if(n%m!=0)
		n=n/m+1;
	else
		n/=m;
	cout<<pow(2,n)-1<<endl;
}

Java Code:

import java.util.Scanner;
public class Main {
	private static int ans=0;
	public static void hanoi(int n,int m,char a,char b,char c) {
		if(n<=m)
			ans++;
		else {
			hanoi(n-m,m,a,c,b);
			ans++;
			hanoi(n-m,m,b,a,c);
		}
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		int m = cin.nextInt();
		hanoi(n,m,'x','y','z');
		System.out.println(ans);
	}
}


蓝桥杯1107 算法训练 蜜蜂飞舞(水题)

原题链接:算法训练 蜜蜂飞舞

  • 思路: 一道水题,求两点间距离。

C++ Code:

#include 
#include 
#include 
using namespace std;
int main(){
    int n;  cin>>n;
    int a,b,c,d,e,f,t;
    int x1=0,y1=0,z1=0,x2=0,y2=0,z2=0;
    for(int i=1;i<=n;i++){
        cin>>a>>b>>c>>d>>e>>f>>t;
        x1+=a*t,y1+=b*t,z1+=c*t;
        x2+=d*t,y2+=e*t,z2+=f*t;
    }
    int sx1,sy1,sz1,sx2,sy2,sz2;
    cin>>sx1>>sy1>>sz1>>sx2>>sy2>>sz2;
    x1+=sx1,y1+=sy1,z1+=sz1;
    x2+=sx2,y2+=sy2,z2+=sz2;
    double ans=sqrt(pow((x1-x2),2)+pow((y1-y2),2)+pow((z1-z2),2));
    printf("%.4f",ans);
}

Java Code:

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		int a,b,c,d,e,f,t;
		int x1=0,y1=0,z1=0,x2=0,y2=0,z2=0;
		while(n-- >0){
			a = cin.nextInt(); b = cin.nextInt();
			c = cin.nextInt(); d = cin.nextInt();
			e = cin.nextInt(); f = cin.nextInt();
			t = cin.nextInt();
			x1+=a*t; y1+=b*t; z1+=c*t;
			x2+=d*t; y2+=e*t; z2+=f*t;
		}
		int xx1 = cin.nextInt(); int yy1 = cin.nextInt();
		int zz1 = cin.nextInt(); int xx2 = cin.nextInt();
		int yy2 = cin.nextInt(); int zz2 = cin.nextInt();
		x1+=xx1; y1+=yy1; z1+=zz1;
		x2+=xx2; y2+=yy2; z2+=zz2;
		double ans = Math.sqrt(Math.pow(x1-x2, 2)+Math.pow(y1-y2, 2)+Math.pow(z1-z2, 2));
		System.out.printf("%.4f\n",ans);
	}
}


蓝桥杯1110 算法训练 数组查找及替换(模拟)

原题链接:算法训练 数组查找及替换

  • 思路: 简单模拟题。ASCII码值可以不用转换为相同类型,直接比较。

Java Code:

import java.util.Arrays;
import java.util.Scanner;
public class Main {
	static int[] a = new int[105];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt(); int b = cin.nextInt();
		for(int i=1;i<=n;i++) 
			a[i] = cin.nextInt();
		Arrays.sort(a,1,n+1);
		for(int i=1;i<=n;i++) {
			if(a[i]%b!=0) {
				if(a[i]>='A'&&a[i]<='Z')
					System.out.print((char)a[i]+" ");
				else
					System.out.print(a[i]+" ");
			}
		}
	}
}


蓝桥杯1132 算法训练 比赛安排(模拟)

原题链接:算法训练 比赛安排

  • 思路: 用一个二维数组 pair[i][j] 来记录 i 队和 j 队是否比赛过,一维数组 team[i] 来记录某轮比赛 i 队是否已经参加过了比赛。对于每轮比赛,要初始化 team 一维数组,但是不能初始化 pair 数组。这道题有点坑的地方就是输出格式应该为 A-B C-D,而不是 “,” 。

Java Code:

import java.util.Arrays;
import java.util.Scanner;
public class Main {
	static int[][] pair = new int[70][70];
	static int[] team = new int[70];
	static int n;
	static void race() {
		int x=0;
		Arrays.fill(team, 0);
		for(int i=1;i<=n;i++) {
			for(int j=i+1;j<=n;j++) {
				if(pair[i][j]==0 && team[i]==0 && team[j]==0) {
					x++;
					team[i]=1; team[j]=1; pair[i][j]=1;
					System.out.print(i+"-"+j+" ");
				}
				if(x==n/2)	return;
			}
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		n = cin.nextInt();
		n = (int) Math.pow(2, n);
		for(int k=1;k<n;k++) {
			System.out.printf("<%d>",k);
			race();
			System.out.println();
		}
	}
}


蓝桥杯1133 算法训练 字符串编辑(模拟)

原题链接:算法训练 字符串编辑

  • 思路: 简单模拟题。有三种操作,删除,插入和替换。插入的话要分三种情况,分别是不存在指定字符,存在一个指定字符以及存在多个指定字符。其他两种均存在两种字符,分别是不存在指定字符以及存在指定字符。

Java Code:

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		// TODO Auto-generated method stub\
		Scanner cin = new Scanner(System.in);
		String s1 = cin.nextLine();
		String s2 = cin.nextLine();
		char ch = s2.charAt(0);
		if(ch=='D') {
			int x = -1;
			x = s1.indexOf(s2.charAt(2));
			if(x==-1)
				System.out.println("指定字符不存在");
			else 
				System.out.println(s1.replaceFirst(s1.substring(x, x+1), ""));
		}else if(ch=='I') {
			int sum=0,x = -1;
			for(int i=0;i<s1.length();i++) {
				if(s1.charAt(i)==s2.charAt(2))	
					sum++;
			}
			if(sum==0)
				System.out.println("指定字符不存在");
			else if(sum==1){
				x = s1.indexOf(s2.charAt(2));
				System.out.println(s1.substring(0,x)+s2.charAt(4)+s1.substring(x));
			}else {
				for(int i=s1.length()-1;i>=0;i--) {
					if(s1.charAt(i)==s2.charAt(2)) {
						x = i;
						break;
					}
				}
				System.out.println(s1.substring(0,x)+s2.charAt(4)+s1.substring(x));
			}
				
		}else if(ch=='R') {
			int x = -1;
			x = s1.indexOf(s2.charAt(2));
			if(x==-1)
				System.out.println("指定字符不存在");
			else
				System.out.println(s1.replace(s1.substring(x, x+1), s2.substring(4,5)));
		}
	}
}


你可能感兴趣的:(蓝桥杯)