难度由小到大
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;
}
}