目录
一、煤球数目
思路:
分析可知: 每一层的煤球数量=上一层的煤球数量+当前层数
答案:
171700
代码:
import java.io.IOException;
import java.io.PrintWriter;
public class Main {
static PrintWriter pw=new PrintWriter(System.out);
static int a[]=new int[110];//存储每层的煤球个数
public static void main(String args[]) throws IOException{
int res=0;
for(int i=1;i<=100;i++){
a[i]=a[i-1]+i;
res+=a[i];
}
pw.println(res);
pw.close();
}
}
二、生日蜡烛
思路:
设开始生日party时年龄为x,一共举办了n次,则吹熄的蜡烛数为x、x+1、x+2、x+3 ····x+n-1,共nx+n(n-1)/2,枚举x和n使其等于236即可
答案:
26
代码:
import java.io.IOException;
import java.io.PrintWriter;
public class Main {
static PrintWriter pw=new PrintWriter(System.out);
public static void main(String args[]) throws IOException{
for(int n=1;n<=100;n++){
for(int x=1;x<=100;x++){
if(n*(n-1)%2==0 && n*x+n*(n-1)/2==236)
pw.println(x);
}
}
pw.close();
}
}
三、凑算式
该官网题目出错了,原题中A~I代表1~9的数字而不是0~9的数字
思路:
由6+8/3+952/714=10可知,不能直接利用整数除法下取整来做,将两个分式进行通分
因此将等式转变为 A+(B*(GHI)+C*(DEF))/(C*(GHI))=10 且 (B*(GHI)+C*(DEF))必须是(C*(GHI))的整数倍
答案:
29
代码:
import java.io.IOException;
import java.io.PrintWriter;
public class Main{
static PrintWriter pw=new PrintWriter(System.out);
static int N=20;
static int a[]=new int[N];
static boolean flag[]=new boolean[N];
static int res=0;
public static boolean check(){
int x1=a[0];
int x2=a[1];
int x3=a[2];
int x4=a[3]*100+a[4]*10+a[5];
int x5=a[6]*100+a[7]*10+a[8];
if((x2*x5+x3*x4)%(x3*x5)==0 && x1+(x2*x5+x3*x4)/(x3*x5)==10) return true;
return false;
}
public static void dfs(int u){
if(u==9){
if(check()) res++;
return;
}
for(int i=1;i<=9;i++){
if(!flag[i]){
flag[i]=true;
a[u]=i;
dfs(u+1);
flag[i]=false;
}
}
}
public static void main(String args[]) throws IOException{
dfs(0);
pw.println(res);
pw.close();
}
}
六、方格填数
思路:
dfs枚举全排列,分别判断每种情况是否相邻
判断是否相邻,即查看这两个位置的数的绝对值的差是否为1
答案:
1580
代码:
import java.io.IOException;
import java.io.PrintWriter;
public class Main {
static PrintWriter pw=new PrintWriter(System.out);
static int N=10;
static int a[]=new int[N];
static boolean flag[]=new boolean[N];
static int res=0;
public static boolean check(){
if(Math.abs(a[0]-a[1])==1) return false;
if(Math.abs(a[0]-a[3])==1) return false;
if(Math.abs(a[0]-a[4])==1) return false;
if(Math.abs(a[0]-a[5])==1) return false;
if(Math.abs(a[1]-a[2])==1) return false;
if(Math.abs(a[1]-a[4])==1) return false;
if(Math.abs(a[1]-a[5])==1) return false;
if(Math.abs(a[1]-a[6])==1) return false;
if(Math.abs(a[2]-a[5])==1) return false;
if(Math.abs(a[2]-a[6])==1) return false;
if(Math.abs(a[3]-a[4])==1) return false;
if(Math.abs(a[3]-a[7])==1) return false;
if(Math.abs(a[3]-a[8])==1) return false;
if(Math.abs(a[4]-a[5])==1) return false;
if(Math.abs(a[4]-a[7])==1) return false;
if(Math.abs(a[4]-a[8])==1) return false;
if(Math.abs(a[4]-a[9])==1) return false;
if(Math.abs(a[5]-a[6])==1) return false;
if(Math.abs(a[5]-a[8])==1) return false;
if(Math.abs(a[5]-a[9])==1) return false;
if(Math.abs(a[6]-a[9])==1) return false;
if(Math.abs(a[7]-a[8])==1) return false;
if(Math.abs(a[8]-a[9])==1) return false;
return true;
}
public static void dfs(int u){
if(u==10){
if(check()) res++;
return;
}
for(int i=0;i<=9;i++){
if(!flag[i]){
flag[i]=true;
a[u]=i;
dfs(u+1);
flag[i]=false;
}
}
}
public static void main(String args[]) throws IOException{
dfs(0);
pw.println(res);
pw.close();
}
}
七、剪邮票
思路:
将原题重新进行编码,转换的数的下标如上图所示,便于判断两点是否相连(两个数的绝对值相差1或者5即代表相连)
dfs枚举五个数,共种情况,判断每种情况的五个数字都相连即可
判断五个数字是否相连,利用并查集的思想,若两个数相连,则将其合并,最后判断这五个数是否合并为一堆,若为1则代表这五个数相连
相连的情况,最后合并为一堆,即连通块数量为1
不相连情况,最后堆数大于1,即连通块数量大于1
答案:
116
代码:
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class Main {
static PrintWriter pw=new PrintWriter(System.out);
static int N=20;
static int b[]={1,2,3,4,6,7,8,9,11,12,13,14};
static boolean flag[]=new boolean[N];
static int a[]=new int[N];
static int c[]=new int[N];
static int p[]=new int[N];
static Set<Integer>set=new HashSet<>();
public static int find(int x){//并查集
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
public static boolean check(int c[]){
for(int i=0;i<5;i++) p[i]=i;
for(int i=0;i<5;i++){
for(int j=i+1;j<5;j++){
if((find(i)!=find(j)) && (Math.abs(c[i]-c[j])==5 || Math.abs(c[i]-c[j])==1)){
p[find(j)]=find(i);//合并
}
}
}
int res=0;
for(int i=0;i<5;i++){//查找一共有几堆
if(p[i]==i) res++;
}
return res==1;
}
public static void dfs(int u){
if(u==5){
c=Arrays.copyOf(a,5);//由于次数是C12 5而不是A12 5,因此不考虑顺序,将这五个数进行排序
Arrays.sort(c,0,5);
int x=c[0]*10000+c[1]*1000+c[2]*100+c[3]*10+c[4];
if(check(c)) set.add(x);
return;
}
for(int i=0;i<b.length;i++){
if(!flag[i]){
flag[i]=true;
a[u]=b[i];
dfs(u+1);
a[u]=0;
flag[i]=false;
}
}
}
public static void main(String args[]) throws IOException{
dfs(0);
pw.println(set.size());
pw.close();
}
}
八、四平方和
思路:
首先想到暴力枚举四层循环,但时间复杂度为0(n^4),不可取,需要进行优化
考虑空间换时间,定义node类,存储c,d,sum,首先枚举c,d,预处理出c,d,,存储在链表中,按照sum从小到大排序,然后枚举a,b,同时计算n-a*a-b*b的差值x,二分查找链表,若能够找到sum=x,则此时即a,b,c,d即是答案
代码:
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Main {
static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter pw=new PrintWriter(System.out);
public static int nextInt() throws IOException{
st.nextToken();
return (int)st.nval;
}
static class node implements Comparable<node>{
int c,d,sum;
public node(int c,int d,int sum){
this.c=c;
this.d=d;
this.sum=sum;
}
public int compareTo(node p){
return Integer.compare(sum,p.sum);
}
}
static int n;
static List<node>list=new ArrayList<>();
public static void main(String args[]) throws IOException{
n=nextInt();
int cnt=0;
for(int c=0;c*c<=n/2;c++){
for(int d=c;c*c+d*d<=n;d++){
list.add(new node(c,d,c*c+d*d));
}
}
Collections.sort(list);
for(int a=0;a*a<=n/4;a++){
for(int b=a;a*a+b*b<=n/2;b++){
int x=n-a*a-b*b;
int l=0,r=list.size()-1;
while (l<r){
int mid=l+r>>1;
if(list.get(mid).sum>=x) r=mid;
else l=mid+1;
}
if(list.get(r).sum==x){
int c=list.get(r).c;
int d=list.get(r).d;
pw.println(a+" "+b+" "+c+" "+d);
pw.close();
return;
}
}
}
}
}
九、取球博弈
思路:
递归+记忆化搜索
f[num][me][you]共三维状态,num为当前小球的剩余数,me表示此时我手中球的个数是否为奇数,1表示为奇数,0表示为偶数,you同理;
代码:
import java.io.*;
import java.util.Arrays;
public class Main{
static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter pw=new PrintWriter(System.out);
public static int nextInt() throws IOException{
st.nextToken();
return (int)st.nval;
}
static int n;
static int N=1010;
static int f[][][]=new int[N][2][2];
static int a[]=new int[3];
public static int dfs(int num,int me,int you){//num为当前剩余球的个数,me:0代表我有偶数个球,1代表我有奇数个球,you同理
if(f[num][me][you]!=0) return f[num][me][you];
if(num<a[0]){//最小的都不够拿
if((me&1) == (you&1)) return 2;//同奇或同偶,平局
else if((me&1)==1) return 1;//赢
return -1;//输
}
else{
boolean nowin=false;
for(int i=2;i>=0;i--){
if(num<a[i]) continue;
int res=dfs(num-a[i],you,(me+a[i])&1);//对方结果
if(res==-1) return f[num][me][you]=1;
if(res==2) nowin=true;
}
if(nowin) return f[num][me][you]=2;//所有情况都无法取胜的前提下,平局;
return f[num][me][you]=-1;
}
}
public static void main(String args[]) throws IOException{
for(int i=0;i<3;i++) a[i]=nextInt();
Arrays.sort(a);
for(int i=1;i<=5;i++){
n=nextInt();
int res=dfs(n,0,0);
if(res==1) pw.print("+ ");
else if(res==-1) pw.print("- ");
else pw.print("0 ");
}
pw.close();
}
}
十、压缩变换
思路:
首先考虑暴力做法,用map来记录每个数即其上一次出现的下标t,若当前数之前从未出现过,则将a[i]变为其相反数;否则,从t+1开始到i-1,将每个数都加入到set中,最终set的大小即是两数中间的种类数,将a[i]=set.size(),最终输出a[i]即可;时间复杂度为0(n^2),会超时,在蓝桥杯官网上过了四个测试用例(4/8)
利用树状数组进行优化,时间复杂度0(nlogn),具体详见代码注释
代码一 暴力做法:
import java.io.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Main {
static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter pw=new PrintWriter(System.out);
public static int nextInt() throws IOException{
st.nextToken();
return (int)st.nval;
}
static int n;
static int N=100010;
static int a[]=new int[N];
static Map<Integer,Integer>map=new HashMap<>();
public static void main(String args[]) throws IOException{
n=nextInt();
for(int i=1;i<=n;i++) a[i]=nextInt();
for(int i=1;i<=n;i++){
int x=a[i];
if(map.get(x)==null){//之前未出现过
pw.print(-a[i]+" ");
}
else{
int t=map.get(x);//上次x出现的位置
Set<Integer> set=new HashSet<>();
for(int j=t+1;j<i;j++) set.add(a[j]);
pw.print(set.size()+" ");
}
map.put(x,i);
}
pw.close();
}
}
代码二 树状数组优化
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class Main {
static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter pw=new PrintWriter(System.out);
public static int nextInt() throws IOException{
st.nextToken();
return (int)st.nval;
}
static int n;
static int N=100010;
static int a[]=new int[N];
static int tr[]=new int[N];
static Map<Integer,Integer>map=new HashMap<>();
public static int lowbit(int x){
return x&-x;
}
public static void add(int x,int v){
for(int i=x;i<N;i+=lowbit(i)) tr[i]+=v;
}
public static int query(int x){
int res=0;
for(int i=x;i>=1;i-=lowbit(i)) res+=tr[i];
return res;
}
public static void main(String args[]) throws IOException{
n=nextInt();
for(int i=1;i<=n;i++) a[i]=nextInt();
for(int i=1;i<=n;i++){
int x=a[i];
if(map.get(x)==null){//之前未出现过
a[i]=-a[i];
add(i,1);
}
else{
int t=map.get(x);//上次出现的位置
add(t,-1);
add(i,1);
a[i]=query(i-1)-query(t);
}
map.put(x,i);
}
for(int i=1;i<=n;i++) pw.print(a[i]+" ");
pw.close();
}
}