难度由低到高
1.饮料换购
来源:第六届蓝桥杯省赛C++A组
题目链接
题解:这题比较简单,我们直接看代码
c++代码:
#include<iostream>
#include<math.h>
using namespace std;
const int N=10000+10;
int main()
{
int n;
int ans=0;
cin>>n;
ans+=n;//最初的n瓶,直接加
//现在我们有n个瓶盖
while(n>=3)//小于3个瓶盖,没办法换了,直接退出
{
ans+=n/3;//可以换n/3瓶
n=n/3+n%3;//n/3是上面换的,因为已经加到ans里去了,这里n/3还是瓶盖的数量 ,n%3是因为不满3个剩下的 所以要加上;
}
cout<<ans<<endl;
}
java代码:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int ans=0;
int n;
n=sc.nextInt();
ans+=n;//最初的n瓶,直接加
//现在我们有n个瓶盖
while(n>=3) {
//小于3个瓶盖,没办法换了,直接退出
ans += n/3;//可以换n/3瓶
n = n / 3 + n % 3;//n/3是上面换的,因为已经加到ans里去了,这里n/3还是瓶盖的数量 ,n%3是因为不满3个剩下的 所以要加上;
}
System.out.println(ans);
}
}
2.连号区间数
来源:第四届蓝桥杯省赛C++B组
题目链接
题解:首先解释下什么是连续,假设有5 4 3 1 2这个数列,从5到3 我们进行排序后得 3 4 5 是连续的 所有是一个连号区间 同理 5 4也是 ,数字本身到数字本身也是,但 5 4 3 1 不是,因为排序后为1 3 4 5不连续;
这题的解题关键在于假设有n个数,则着n个数分别为1~n之间的数,且每个数字都出现,且仅出现一次,那一个区间要连续的充要条件则是这个区间的最大值减去最小值加一等于区间的长度,为什么,因为这个区间里的所有数一定包含在最大值最小值之间,且他们不重复,那么当最大值减去最小值加一等于区间的长度时,只有可能是他们连续,不然无法满足;
c++代码:
#include<iostream>
#include<math.h>
using namespace std;
const int N=10000+10;
int main()
{
int a[N];
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int ans=0;
for(int i=1;i<=n;i++)//2个for 遍历数列的开头和结尾
{
max1=0;
min1=11000;
for(int j=i;j<=n;j++)
{
max1=max(a[j],max1);//更新最大值,最小值
min1=min(a[j],min1);
if((max1-min1)==(j-i))2个都省去了一个加一
{
ans++;
}
}
}
cout<<ans<<endl;
}
java代码:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
final int N=10000+10;
int []a=new int [N];
int n;
n=sc.nextInt();
for(int i=1;i<=n;i++)
a[i]=sc.nextInt();
int ans=0;
for(int i=1;i<=n;i++)
{
int max1=0;
int min1=11000;
for(int j=i;j<=n;j++)
{
max1=Math.max(a[j],max1);
min1=Math.min(a[j],min1);
if((max1-min1)==(j-i))//2个都省去了一个加一
{
ans++;
}
}
}
System.out.println(ans);
}
}
3.等差数列
来源:第十届蓝桥杯省赛C++B组
题目链接
题解:相信大家都知道等差数列,它有一个公差,也就是说数列任意2个数之差都是某个数的倍数,为了让数列尽可能的小,对于等差数列而已,我们就是要让它的公差尽可能的大,那么我们要做的就是求所有相邻两项之差所得的数的最大公因数,也就是辗转相除法
c++代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100000;
int zzxc(int x,int y)//辗转相除法
{
while (1)
{
if(x>y)
{
x=x%y;
if(x==0)
return y;
}
else
{
y=y%x;
if(y==0)
return x;
}
}
}
int main()
{
int a[N];
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+n+1);
int cha=a[2]-a[1];
for(int i=2;i<n;i++)
{
if(a[i+1]-a[i]==0)//2数相等,一定是一个公差为0的数列
{
cha=0;
break;
}
cha=zzxc(cha,a[i+1]-a[i]);//cha为前面所有项的最大公因数
}
if(cha!=0)
cout<<(a[n]-a[1])/cha+1<<endl;
else
cout<<n<<endl;
}
java代码:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
final int N=100000+10;
int n;
int []a=new int[N];
n=sc.nextInt();
for(int i=1;i<=n;i++)
a[i]=sc.nextInt();
Arrays.sort(a,1,n+1);
int cha=a[2]-a[1];
for(int i=2;i<n;i++)
{
if(a[i+1]-a[i]==0)//2数相等,一定是一个公差为0的等差数列
{
cha=0;
break;
}
cha=zzxc(cha,a[i+1]-a[i]);//cha为前面所有项的最大公因数
}
if(cha==0)
System.out.println(n);
else
System.out.println((a[n]-a[1])/cha+1);
}
static int zzxc(int x ,int y)//辗转相除法
{
while (true)
{
if(x>y)
{
x=x%y;
if(x==0)
return y;
}
else
{
y=y%x;
if(y==0)
return x;
}
}
}
}
4.生命之树
来源:第六届蓝桥杯省赛C++B组
题目链接
题解:树形dp模板题(树形dp讲解)
c++代码:
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 100010,M=N*2;
int h[N],e[M],ne[M],w[N],idx;
int n;
LL f[N];
void add(int a,int b)
{
e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
void dfs(int u,int father)
{
f[u]=w[u];
for(int i=h[u];~i;i=ne[i])
{
int j = e[i];
if(j!=father)
{
dfs(j,u);
f[u]+=max(0ll,f[j]);
}
}
}
int main()
{
cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<=n;++i)cin>>w[i];
for(int i=0;i<n-1;++i){
int a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
dfs(2,-1);
LL res = f[1];
for(int i=2;i<=n;++i)res = max(res,f[i]);
cout<<res<<endl;
return 0;
}
java代码:
import java.util.*;
public class Main {
private static int n;
private static long res;
private static long[] w;
private static List<Integer>[] g;
private static long[] f ;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n =sc.nextInt();
w = new long[n+1];
g = new ArrayList[n+1];
f = new long[n+1];
for(int i = 0;i < n+1; i++){
g[i] = new ArrayList<Integer>();
}
for(int i = 1;i <= n;i ++){
w[i] = sc.nextLong();
}
for(int i = 0;i < n - 1;i ++)
{
int a = sc.nextInt();
int b = sc.nextInt();
g[a].add(b);
g[b].add(a);
}
dfs(1,0);
res = f[1];
for(int i = 2; i < n+1; i++){
if(res<f[i]){
res = f[i];
}
}
System.out.println(res);
}
/**
*root作为根所代表的子树有一个最大权和,将其存储在f[root]中
*/
private static void dfs(int root,int father){
f[root] = w[root];
for(int i = 0; i < g[root].size(); i++){
Integer child = g[root].get(i);
if(child == father){
continue;
}
dfs(child,root);
if(f[child] > 0){
f[root] += f[child];
}
}
}
}