蓝桥杯

寄巧

双端队列模拟栈和队列Deque<Integer> queue=new ArrayDeque<>();

queue.offer(last) //入队
queue.poll() //出队
queue.peek() //查看队首元素
queue.

需要排序用优先队列,PriorityQueue默认是小根堆

Comparator<Integer> cp=(o1,o2)-> o2-o1; //比较器
PriorityQueue<Integer> pq=new PriorityQueue<Integer>(cp);

Integer.toString(i);str.charAt(j)-'0';来正着取一个数的每一位
Integer.parseInt(s2.substring(0, id));将全是数字的字符串转为int变量
s.contains("-")判断字符串中是否存在字符
String s1[]=s.split("=");以=为分界线分开字符串
Double.MAX_VALUE;表示Double的最大值
Arrays.sort(range, 0, n)数组排序范围是左闭右开,也就是[0,n)

//MAP的操作
HashMap<Integer,Integer> map=new HashMap<Integer, Integer>();
map.put(t,map.getOrDefault(t, 0)+1);

注意int的最大为2e9,long为1e18

对数组进行自定义排序

Arrays.sort(people, (a, b) -> a.age - b.age);//前-后,为升序排序

Comparable接口

  • this-other为升序,ohter-this为降序

    public int compareTo(Student other) {
        return this.score - other.score; // 升序
    }
    
  • 在这个例子中,是按照r来升序排序。Integer.compare(r, o.r);相当于r-o.r

    class Range implements Comparable<Range>{
    	int l,r;
    	public Range(int l,int r)
    	{
    		this.l=l;
    		this.r=r;
    	}
    	public int compareTo(Range o)
    	{
    		return Integer.compare(r, o.r);
    	}
    }
    

每日一题

农夫约翰的奶酪块(用二维模拟三维)

image-20250406185213225

import java.util.*;
public class Main {
    static int N=1020,n,q,ans;
    static int[][] xy=new int[N][N],yz=new int[N][N],xz=new int[N][N];
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        n=scan.nextInt();
        q=scan.nextInt();
        while (q-- > 0)
        {
            int x= scan.nextInt();
            int y= scan.nextInt();
            int z= scan.nextInt();
            if((++xy[x][y])==n) ans++;
            if((++yz[y][z])==n) ans++;
            if((++xz[x][z])==n) ans++;
            System.out.println(ans);
        }

    }
}

哞叫时间(枚举)

image-20250406185504555

先枚举哪一位变,再枚举变了之后的叫声

import javax.swing.*;
import java.util.*;
public class Main {
    static int N=20010,n,f,ans;
    static int [] str=new int[N],str1=new int[N];
    static int[][] cont=new int[26][26],cont1=new int[26][26];
    static boolean[][] st=new boolean[26][26];
    static String line="";
    static boolean checkstr(int i)
    {
        return str[i]!=26&&str[i+1]!=26&&str[i+2]!=26;
    }
    static void check()
    {
        for(int i=0;i<26;i++)
            for(int j=0;j<26;j++) cont1[i][j]=0;
        for(int i=0;i<n-2;i++)
        {
            if(str1[i+1]==str1[i+2]&&str1[i]!=str1[i+1])
            {
                cont1[str1[i]][str1[i+1]]++;
//                System.out.println(cont1[str1[i]][str1[i+1]]+" "+(char)(str1[i]+'a')+(char)(str1[i+1]+'a')+(char)(str1[i+2]+'a'));
                if(cont1[str1[i]][str1[i+1]]>=f&&!st[str1[i]][str1[i+1]])
                {
//                    System.out.println(cont1[str1[i]][str1[i+1]]+" "+(char)(str1[i]+'a')+(char)(str1[i+1]+'a')+(char)(str1[i+2]+'a'));
                    st[str1[i]][str1[i+1]]=true;
                    ans++;
                }
            }
        }
    }

    static void print()
    {
        for(int i=0;i<n;i++)
        {
            System.out.print((char)(str1[i]+'a')+" ");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        n= scan.nextInt();
        f= scan.nextInt();
        line=scan.next();
        for(int i=0;i<n;i++)
        {
            str[i]=(int)line.charAt(i)-'a';
//            System.out.print(str[i]+" ");
        }
//        System.out.println();
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                str1[j]=str[j];
            }
            for(int j=0;j<=25;j++)
            {
                str1[i]=j;
//                print();
                check();
            }
        }
        System.out.println(ans);
        for(int i=0;i<26;i++)
            for(int j=0;j<26;j++)
            {
                if(st[i][j]) System.out.println(""+(char)(i+'a')+(char)(j+'a')+(char)(j+'a'));
            }

    }
}

哞叫时间II(枚举)

image-20250406185738284

先从前往后枚举每个数字出现多少次,用l[]来表示这个数出现的次数。
然后从后向前枚举每个数字,用r[]表示每个数字出现的次数,每次枚举都让l[]对应的数减1,如果减到0就说明这个数字不在左边了。

import java.io.*;
import java.util.*;
public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));

    static int N=(int)1e6+3,n;
    static long ans;
    static int[] l=new int[N],r=new int[N];

    public static void main(String[] args) throws IOException {
        n=nextInt();
        int[] a=new int[n+1];
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            a[i]=nextInt();
            l[a[i]]++;
            if(l[a[i]]==1) cnt++;
        }
        for(int i=n;i>=1;i--)
        {
            l[a[i]]--;r[a[i]]++;
            if(l[a[i]]==0) cnt--;
            if(r[a[i]]==2)
            {
                ans+=cnt;
                if(l[a[i]]!=0) ans--;
            }
        }
        cout.println(ans);
        cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll()
    {
        cout.close();
    }
}

试除法求约数

package Main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    
    static ArrayList<Integer> get_divisors(int n)
    {
    	ArrayList<Integer> list=new ArrayList<Integer>();
    	for(int i=1;i<=n/i;i++)
    		if(n%i==0)
    		{
    			list.add(i);
    			if(i!=n/i) list.add(n/i);
    		}
    	Collections.sort(list)
    	return list;
    }
    
    public static void main(String[] args) throws IOException {
        int n=nextInt();
        
        while(n-- > 0)
        {
        	int x;
        	x=nextInt();
        	ArrayDeque<Integer> queue=get_divisors(x);
        	for(Integer t:queue) cout.print(t+" ");
        	cout.println();
        }
        
        cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}

14届Java B

互质(快速幂求逆元,容斥原理,互质定义)

image-20250604213836882

image-20250604214234129

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;


public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	
	static int N=20,INF=0x3f3f3f3f,MOD=1000000007;
	static int[] p=new int[N];
	
	static long qmi(int m,int k)
	{
		long res=1,t=m;
		while(k!=0)
		{
			if((k&1)==1) res=res*t%MOD;
			t=t*t%MOD;
			k>>=1;
		}
		return res;
	}
	
	
    public static void main(String[] args) throws IOException 
    {
    	long sum=qmi(2023,2023);
    	long a=sum*qmi(7,MOD-2)%MOD;
    	long b=sum*qmi(17,MOD-2)%MOD;
    	long c=sum*qmi(7*17,MOD-2)%MOD;
    	
//    	long a=(sum/7)%MOD;
//    	long b=(sum/17)%MOD;`
//    	long c=(sum/qmi(7*17,MOD-2))%MOD;
    	
    	long ans=(sum-(a+b-c)+2*MOD)%MOD;
    	
    	cout.print(ans);
    	
    	cout.flush();
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 看到\(2023^{2023}\)不要怕,因为有MOD 1e9+7 ,所以用快速幂一定可以求出来
  2. 两个数互质,则两个数没有除 1 以外的其他公约数。如果两个数是素数,则一定互质

逆元(快速幂求逆元,暴力)

image-20250605112031429

直接用快速幂求逆元,然后暴力就行,就是时间需要一两分钟左右

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;


public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	
	static int N=20,INF=0x3f3f3f3f,MOD=2146516019;
	static int[] p=new int[N];
	
	static long qmi(long m,long k)
	{
		long res=1,t=m;
		while(k!=0)
		{
			if((k&1)==1) res=res*t%MOD;
			t=t*t%MOD;
			k>>=1;
		}
		return res;
	}
	
	
    public static void main(String[] args) throws IOException 
    {
    	long res=0;
    	for(long i=1;i<=233333333;i++)
    	{
    		long t=qmi(i,2146516019-2);
    		cout.println(t);
    		res^=t;
    		
    	}
    	cout.print("-------------------------");
    	cout.print(res);
    	cout.flush();
    	
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 这里比较凑巧了,正好在运行,然后就拿笔想算一下怎么算的,正在想就算出来了。

玩具(贪心)

image-20250605163658882

一开始根据题意想到区间dp中的石子合并问题,但是那个问题是要求只能合并相邻两个,而这里没有这个限制,同时那个要求合并为一堆,这个不需要。这里和哈夫曼树的合并果子问题也不一样

这里的思路是先排序,然后取最大和最小的乘积贡献到答案中即可。


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;


public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	
	static int N=2000005,n;
	static long[] w=new long[N];
	
    public static void main(String[] args) throws IOException 
    {
    	n=nextInt();
    	for(int i=0;i<2*n;i++) w[i]=nextInt();
    	
    	Arrays.sort(w,0,2*n);
//    	for(int i=0;i<2*n;i++) cout.println(w[i]);
    	long res=0;
    	for(int i=0,j=2*n-1;i<j;i++,j--)
    	{
    		res+=w[i]*w[j];
//    		cout.println(w[i]+" "+w[j]);
    	}
    	
    	cout.println(res);
    	
    	cout.flush();
    	
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}

不完整的算式(大模拟)

image-20250606192351320image-20250606192401105

没有用API写的

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;


public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    
    static String str;
    static char[] c;
    static int get_num(int st,int ed)
    {
        int t=1;
        int num=0;
        for(int i=ed-1;i>=st;i--) 
        {
            num+=(c[i]-'0')*t;
            t*=10;
        }
        return num;
    }
    
    public static void main(String[] args) throws IOException 
    {
        str=bf.readLine();
        char[] c=str.toCharArray();
        int sym=0;
        while((c[sym]<='9'&&c[sym]>='0')||c[sym]=='?') sym++;
//        cout.println(sym+" "+c[sym]);
        if(c[sym]=='=') //1?1=2
        {
            int eq=sym;
            sym=0;
            while(c[sym]<='9'&&c[sym]>='0') sym++;
//            cout.println(sym+" "+c[sym]);
//            cout.println(eq+" "+c[eq]);
            
            long num1=0,num2=0,num3=0;
            long t=1;
            for(int i=sym-1;i>=0;i--) 
            {
                num1+=(c[i]-'0')*t;
                t*=10;
            }
            
            t=1;
            for(int i=eq-1;i>sym;i--) 
            {
                num2+=(c[i]-'0')*t;
                t*=10;
            }
            
            t=1;
            int ed=str.length();
            for(int i=ed-1;i>eq;i--) 
            {
                num3+=(c[i]-'0')*t;
                t*=10;
            }
            
//            cout.println(num1+" "+num2+" "+num3);
            
            if(num1+num2==num3) cout.println("+");
            else if(num1-num2==num3) cout.println("-");
            else if(num1*num2==num3) cout.println("*");
            else cout.println("/");
        }
        else
        {
            int num1=0,num2=0,num3=0;
            int t=1;
            int que=0;
            while((c[que]<='9'&&c[que]>='0')||c[que]=='+'||c[que]=='-'||c[que]=='*'||c[que]=='/'||c[que]=='=') que++;
//            cout.println(que+" "+c[que]);
            
            int eq=str.length()-1;
            while((c[eq]<='9'&&c[eq]>='0')||c[eq]=='?') eq--;
//            cout.println(eq+" "+c[eq]);
            
            if(que<eq&&que>sym) //1+?=2
            {
                for(int i=sym-1;i>=0;i--)
                {
                       num1+=(c[i]-'0')*t;
                    t*=10;
                }
                t=1;
                int ed=str.length();
                for(int i=ed-1;i>eq;i--) 
                {
                    num3+=(c[i]-'0')*t;
                    t*=10;
                }
//                cout.println(num1+" "+num2+" "+num3);
                if(c[sym]=='+')
                {
                    num2=num3-num1;
                    cout.println(num2);
                }
                else if(c[sym]=='-')
                {
                    num2=num1-num3;
                    cout.println(num2);
                }
                else if(c[sym]=='*')
                {
                    num2=num3/num1;
                    cout.println(num2);
                }
                else
                {
                    num2=num1/num3;
                    cout.println(num2);
                }
            }
            else if(sym<eq&&eq<que) //1+1=?
            {
                for(int i=sym-1;i>=0;i--)
                {
                       num1+=(c[i]-'0')*t;
                    t*=10;
                }
                
                t=1;
                for(int i=eq-1;i>sym;i--) 
                {
                    num2+=(c[i]-'0')*t;
                    t*=10;
                }
                
//                cout.println(num1+" "+num2+" "+num3);
                if(c[sym]=='+') cout.println(num1+num2);
                else if(c[sym]=='-') cout.println(num1-num2);
                else if(c[sym]=='*') cout.println(num1*num2);
                else cout.println(num1/num2);
            }
            else  //?+1=2
            {
                for(int i=eq-1;i>sym;i--)
                {
                       num2+=(c[i]-'0')*t;
                    t*=10;
                }
                
                t=1;
                for(int i=str.length()-1;i>eq;i--) 
                {
                    num3+=(c[i]-'0')*t;
                    t*=10;
                }
//                cout.println(num1+" "+num2+" "+num3);
                if(c[sym]=='+') cout.println(num3-num2);
                else if(c[sym]=='-') cout.println(num2+num3);
                else if(c[sym]=='*') cout.println(num3/num2);
                else cout.println(num2*num3);
            }
        }
        
        
        
        cout.flush();
        
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}

用API写的

import java.util.Scanner;

public class l17135 {
public static void main(String[] args) {
    Scanner scanner=new Scanner(System.in);
    String s=scanner.nextLine();
    //System.out.println(s);
    if(s.contains("+")||s.contains("-")||s.contains("*")||s.contains("/")) {
        //缺ABC
        String s1[]=s.split("=");
        //缺c
        String s2=s1[0];
        if(s1[1].equals("?")) {
            int id=0;
            for(int i=0;i<s2.length();i++) {
                if(s2.charAt(i)<'0'||s2.charAt(i)>'9') {
                    id=i;
                    break;
                }
            }
            int a=Integer.parseInt(s2.substring(0, id));
            int b=Integer.parseInt(s2.substring(id+1, s2.length()));
            if(s.contains("+"))System.out.println(a+b);
            if(s.contains("-"))System.out.println(a-b);
            if(s.contains("*"))System.out.println(a*b);
            if(s.contains("/"))System.out.println(a/b);
        }else {
            //缺ab
            int c=Integer.parseInt(s1[1]);
            int id=0;
            for(int i=0;i<s2.length();i++) {
                if(s2.charAt(i)=='+'||s2.charAt(i)=='-'||s2.charAt(i)=='*'||s2.charAt(i)=='/') {
                    id=i;
                    break;
                }
            }
            int a=0;
            if(s2.charAt(id-1)>='0'&&s2.charAt(id-1)<='9') {
                a=Integer.parseInt(s2.substring(0, id));
                if(s.contains("/"))System.out.println(a/c);
            }else {
                a=Integer.parseInt(s2.substring(id+1, s2.length()));
                if(s.contains("/"))System.out.println(c*a);
            }
            if(s.contains("+"))System.out.println(c-a);
            if(s.contains("-"))System.out.println(c+a);
            if(s.contains("*"))System.out.println(c/a);    
        }    
    }else {//缺+-*/
        String s1[]=s.split("=");
        int c=Integer.parseInt(s1[1]);
        String s2=s1[0];
        int id=0;
        for(int i=0;i<s2.length();i++) {
            if(s2.charAt(i)<'0'||s2.charAt(i)>'9') {
                id=i;
                break;
            }
        }
        int a=Integer.parseInt(s2.substring(0, id));
        int b=Integer.parseInt(s2.substring(id+1, s2.length()));
        //System.out.println(a+" "+b+" "+c);
        if(a+b==c)System.out.println("+");
        if(a-b==c)System.out.println("-");
        if(a*b==c)System.out.println("*");
        if(a/b==c)System.out.println("/");
    }
}
}
  1. s.contains("+")查看字符串有没有某一项
  2. String[] s1=s.split("=");分割字符串,要用字符串数组接收

星球(状压dp,记忆化搜索)

image-20250606192920344

状态表示dp[s][j]

  • 集合:s表示所有星球的状态,为1表示打过。j表示从第j个星球出发。dp[s][j]表示从状态s和星球j出发攻打的最小代价
  • 属性:min

状态计算:

  • dp[s][i]=min(dp[s|(1<<j)][k]+dis(i,j)*range[j].w)s|(1<<j)表示之前如何没打过第j个星球,那就从现在的星球到第j个星球上打。

这里要注意从哪个星球开始,哪个星球的状态为1。
由于我们的写法问题,这里不能虚构出一个距离所有点都为0代价的虚构点,还是要挨个枚举的

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;

class Range{
	double x,y,z,w;
	public Range(double x,double y,double z,double w) {
		this.x=x;
		this.y=y;
		this.z=z;
		this.w=w;
	}
}

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	
	static double dis(Range a,Range b)
	{
		return Math.sqrt(( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z) ));
	}
	
	static double dfs(int s,int i) //初始状态为s,从i星球开始。注意开始的星球状态要为1
	{
		if(s==(1<<n)-1) return 0;
		
		if(dp[s][i]!=-1) return dp[s][i];
		
		double res=Double.MAX_VALUE;
		for(int j=0;j<n;j++)
		{
			if(((s>>j)&1)==1) continue;
			res=Math.min(res,dfs(s|(1<<j),j)+dis(range[i],range[j])*range[j].w );
		}
		
		dp[s][i]=res;
		return res;
		
		
	}
	
	static Range[] range=new Range[20];
	static double[][] dp;
	static int n=0;
	
	
    public static void main(String[] args) throws IOException 
    {
    	n=nextInt();
    	dp=new double[1<<n][n];
    	for(double[] t:dp) Arrays.fill(t, -1);
    	for(int i=0;i<n;i++)
    	{
    		range[i]=new Range(nextDouble(),nextDouble(),nextDouble(),nextDouble());
    	}
    	
    	double ans=Double.MAX_VALUE;
    	
    	for(int i=0;i<n;i++)
    	{
    		ans=Math.min(ans,dfs(0|(1<<i),i));
    	}
    	
    	cout.printf("%.2f",ans);
    	
    	cout.flush();
    	
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}

序列(数学,审题)

image-20250606221534363

这题的审题从一开始就有问题,没读懂题意

  1. 题目说是\((a_i,b_i)\),我理解成是两个序列中任意两个数了
  2. 题目说求\(S_i\)从1到n,也就说有n个b数组,我没看到以为是没有数量限制

具体思路是对于每一个a[i]i从1开始),求与i的最小公倍数,然后用n*i除以最小公倍数得到对于a[i]来说有几个序列。

蓝桥杯14届国赛F题序列-CSDN博客

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
	
	static long n;
	static long[] a;
	
	static long gcd(long a,long b)
	{
		return b!=0?gcd(b,a%b):a;
	}
	static long lcm(long a,long b)
	{
		return a*b/gcd(a,b);
	}
	
    public static void main(String[] args) throws IOException 
    {
    	n=nextInt();
    	a=new long[(int)n+1];

    	long res=0;
    	for(int i=1;i<=n;i++)
    	{
    		a[i]=nextInt();
    		long t=lcm(i,a[i]);
    		res+=((long)i*n)/t;
    	}
    	cout.print(res);

    	cout.flush();
    	
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  • 注意审题,这题一开始审题出问题了!

电动车(kruskal求最小生成树变种)

image-20250607105156112

这里要求一个最小生成树中两个点的最大路径,用kruskal求最小生成树,求的过程中把最大路径算出来即可

package lqb;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;

class Edgs implements Comparable<Edgs>{
	int u,v,w;
	public Edgs(int u,int v,int w)
	{
		this.u=u;this.v=v;this.w=w;
	}

	@Override
	public int compareTo(Edgs o) {
		return this.w-o.w;
	}
}

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
	
	static int N=200010,n,m,w,INF=0x3f3f3f3f;
	static Edgs[] edgs=new Edgs[N];
	static int[] p=new int[N];
	
	public static int find(int x)
	{
		if(p[x]!=x) p[x]=find(p[x]);
		return p[x];
	}
	
	public static int kruskal() {
		Arrays.sort(edgs,0,m);
		for(int i=0;i<=n;i++) p[i]=i;
		int res=0;
		int cnt=0;
		
		for(int i=0;i<m;i++)
		{
			int u=edgs[i].u;
			int v=edgs[i].v;
			int w=edgs[i].w;
			
			int a=find(u),b=find(v);
			if(a!=b)
			{
				p[a]=b;
				res=w;
				cnt++;
			}
		}
//		cout.println(cnt);
		if(cnt<n-1) return -1;
		return res;
		
	}
	
	public static void main(String[] args) throws IOException 
    {
    	n=nextInt();m=nextInt();
    	
    	for(int i=0;i<m;i++)
    	{
    		edgs[i]=new Edgs(nextInt(),nextInt(),nextInt());
    	}
    	
    	int ans=kruskal();
    	
    	cout.println(ans);
    	
    	cout.flush();
    	
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 这里一开始审题又出现问题了,“使得不需要在任何高速公路内补充电量”这句理解成了求最小生成树的权值了。但是这里说的是“任何高速公路内”,不是“任何城市的路途间”

游戏(滑动窗口)

image-20250607121623497

先用单调队列求出每个窗口的最大值和最小值。通过数学关系可以知道, max_listmin_list为每个窗口的最大值和最小值,则总合为n*max_list[1]-(min_list[1]+min_list[2]...min_list[n])+n*max_list[2]-(min_list[1]+min_list[2]...min_list[n])整理一下得到n*(max_list[1]+max_list[2...])-n*(min_list[1]+min_list[2]...)。因为是有n^2 个,所以要除n^2 得到最后答案

package lqb;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;


public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
	
	static int N=100005,n,k;
	static int[] arr=new int[N];
	
	
	public static void main(String[] args) throws IOException 
    {
		n=nextInt();k=nextInt();
		for(int i=0;i<n;i++) arr[i]=nextInt();
		
        // --- 初始化数据结构 ---
        // 最大堆(降序排序):堆顶是当前窗口可能的最大值,存储格式:[value, index]
        PriorityQueue<int[]> max = new PriorityQueue<>((o1, o2) -> o2[0] - o1[0]);
        // 最小堆(升序排序):堆顶是当前窗口可能的最小值,存储格式:[value, index]
        PriorityQueue<int[]> min = new PriorityQueue<>((o1, o2) -> o1[0] - o2[0]);
        // 用于存储每个窗口的最大值和最小值
        List<Integer> max_list = new ArrayList<>();
        List<Integer> min_list = new ArrayList<>();
        
        
        // --- 1. 初始化填充前 div-1 个元素(窗口未满时的预填充)---
        for (int i = 0; i < div - 1; i++) {
            max.add(new int[]{arr[i], i}); // 加入最大堆
            min.add(new int[]{arr[i], i}); // 加入最小堆
        }
        
        // --- 2. 滑动窗口主循环(从 div-1 开始完整覆盖窗口)---
        for (int i = div - 1; i < arr.length; i++) {
            // 2.1 将新元素加入堆
            max.add(new int[]{arr[i], i});
            min.add(new int[]{arr[i], i});
            // 2.2 计算当前窗口最大值
            while (!max.isEmpty()) {
                int[] poll = max.peek();       // 查看堆顶元素
                if (i - poll[1] < div) {       // 如果该元素的索引仍在窗口内
                    max_list.add(poll[0]);     // 存入最大值列表
                    break;
                } else {
                    max.poll();                // 否则移除过期元素,继续检查下一个
                }
            }
            // 2.3 计算当前窗口最小值
            while (!min.isEmpty()) {
                int[] poll = min.peek();
                if (i - poll[1] < div) {       // 检查是否在窗口内
                    min_list.add(poll[0]);     // 存入最小值列表
                    break;
                } else {
                    min.poll();                // 移除过期元素
                }
            }
        }
		
		double ans=0;
		for(int i=0;i<max_list.size();i++)
		{
			ans+=max_list.get(i)-min_list.get(i);
		}
		ans/=max_list.size();
		cout.printf("%.2f",ans);
		
		cout.flush();
		
    	
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  • 滑动窗口主要是检查当前优先队列的第一个是不是在范围内,如果不是就丢掉找下一个,直到在氛围内,不用对于不在范围内但是在有限队列中的数特殊处理

非对称二叉树(dp)

image-20250610120749759

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        // dp[i][j] 表示节点个数为i时,树的最大高度为j时,非对称二叉树的数量
        long[][] dp = new long[n + 1][n + 1];
        dp[1][1] = dp[0][0] = 1;
        // 枚举所有点的数量i
        // 除去根节点后,枚举所有左子树点的数量x,右子树点的数量y
        // 对于左子树枚举所有高度c,对于右子树枚举所有高度d
        // 找到满足题目要求的情况,就将左右两侧的可能情况数量相乘,加入到目标dp中
        for (int i = 2; i <= n; i++) {
            for (int x = 0; x < i; x++) {
                int y = i - x - 1;
                for (int c = 0; c <= x; c++) {
                    for (int d = 0; d <= y; d++) {
                        if (Math.max(c, d) >= k * Math.min(c, d)) {
                            dp[i][Math.max(c, d) + 1] += dp[x][c] * dp[y][d];
                        }
                    }
                }
            }
        }
        long ans = 0;
        for (int i = 1; i <= n; i++) {
            ans += dp[n][i];
        }
        System.out.print(ans);
    }
}

数和游戏(没看,太难)

14届C B

子2023(纯暴力)

image-20250608123112609

解法1(纯暴力)

把字符串拼接到一起,然后从头开始枚举

package lqb;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;


public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
	
	
	public static void main(String[] args) throws IOException 
    {
		StringBuilder str=new StringBuilder();
		for(int i=1;i<=2023;i++)
		{
			str.append(Integer.toString(i));
//			char[] s=Integer.toString(i).toCharArray();
//			for(char t:s)
//			{
//				if(t=='2'||t=='0'||t=='3') str.append(t);
//			}
		}
		long ans=0;
		for(int i=0;i<str.length();i++)
		{
			if(str.charAt(i)!='2') continue;
			
			for(int j=i+1;j<str.length();j++)
			{
				if(str.charAt(j)!='0') continue;
				
				for(int k=j+1;k<str.length();k++)
				{
					if(str.charAt(k)!='2') continue;
					
					for(int l=k+1;l<str.length();l++)
					{
						if(str.charAt(l)!='3') continue;
						ans++;
					}
					
				}
			}
		}
		cout.println(ans);
		cout.flush();
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}

解法2(优化暴力)

加了对每一位的检查,不是203中任意一个数字的话,这个数字毫无意义

	public static void main(String[] args) throws IOException 
    {
		StringBuilder str=new StringBuilder();
		for(int i=1;i<=2023;i++)
		{
			char[] s=Integer.toString(i).toCharArray();
			for(char t:s)
			{
				if(t=='2'||t=='0'||t=='3') str.append(t);
			}
		}
		long ans=0;
		for(int i=0;i<str.length();i++)
		{
			if(str.charAt(i)!='2') continue;
			
			for(int j=i+1;j<str.length();j++)
			{
				if(str.charAt(j)!='0') continue;
				
				for(int k=j+1;k<str.length();k++)
				{
					if(str.charAt(k)!='2') continue;
					
					for(int l=k+1;l<str.length();l++)
					{
						if(str.charAt(l)!='3') continue;
						ans++;
					}
					
				}
			}
		}
		cout.println(ans);
				
		cout.flush();
    }

解法3(子序列计数dp)

定义状态
f[k] 表示当前已经扫描到某个位置,恰好匹配到模式串 “2023” 的前 k 个字符的子序列数。

  • f[0]:已经匹配了空串的方案数(也就是我们用它来启动新的匹配)。
  • f[1]:已经匹配了 "2" 的方案数。
  • f[2]:已经匹配了 "20" 的方案数。
  • f[3]:已经匹配了 "202" 的方案数。
  • f[4]:已经匹配了 "2023" 的方案数(最终答案)。

状态转移
每读到一个字符 c,如果它等于模式串中的某个位置 k 的字符,就把之前匹配到前面 k 个字符的方案数累加到 f[k+1] 上。

if (c == '2') {
  // 新起一个“2”,同时所有已经匹配过 "20" 的都可接下一个 '2'
  f[1] += f[0];
  f[3] += f[2];
}
else if (c == '0') {
  // 所有已经匹配过 '2' 的都可接 '0'
  f[2] += f[1];
}
else if (c == '3') {
  // 所有已经匹配过 "202" 的都可接 '3'
  f[4] += f[3];
}

双子数(埃氏筛,注意int和long最大值)

image-20250608164229723

埃氏筛+枚举,注意枚举的时候p*p*q*q可能会爆long

package lqb;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;


public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
	
	
	public static void main(String[] args) throws IOException 
    {
		long ans=0;
		long L=2333,R=23333333333333L;
		int M=(int)Math.sqrt(R/4);
		ArrayList<Integer> prime=new ArrayList<Integer>();
		boolean[] vis=new boolean[M+1];
		for(int i=2;i<=M;i++)
		{
			if(!vis[i])
			{
				prime.add(i);
				for(long j=1L*i*i;j<=M;j+=i)
				{
					vis[(int)j]=true;
				}
			}
		}
		for(int i=0;i<prime.size();i++)
		{
			long p=prime.get(i);
			for(int j=i+1;j<prime.size();j++)
			{
				long q=prime.get(j);
				long ppq=p*p*q; //注意这里直接用ppqq,long可能溢出,所以要
				long ppqq=ppq*q;
				if(ppq>R||ppqq>R) break;
				if(ppqq>=L) ans++;
			}
		}
		cout.print(ans);
		
		
		
		cout.flush();
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  • 注意在算的时候有没有可能超过int或long的最大值

班级活动(思维,读题)

image-20250610115304953

package lqb;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.HashMap;


public class Main {
//	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
//	static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
	
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
	
	static int N=100005,n;
	static int[] a;
	
	public static void main(String[] args) throws IOException 
    {
		n=nextInt();
		a=new int[n];
		Arrays.fill(a, 0);

		HashMap<Integer,Integer> map=new HashMap<Integer, Integer>();
		for(int i=0;i<n;i++)
		{
			int t=nextInt();
			map.put(t,map.getOrDefault(t, 0)+1);
		}
		
		int ans=0;
		int x=0,y=0;
		for(int a:map.values())
		{
			if(a>2) x+=a-2;
			else if(a<2) y+=a;
		}
		
		if(x>=y) ans=x;
		else ans=x+(y-x)/2;
		
		cout.println(ans);
		
		cout.flush();
		
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}

合并数列(思维,双指针)

首先注意这个题目只要求操作次数就行

当两个数不相同的时候,只能向后合并,因为前面的已经合并完了。

合并数可以不用非得把那些数合并,可以用cnt来表示那个区间的数之和来替代合并的数。

如果cnt1<cnt2,则a数组的那个数需要向后合并一个数。cnt1>cnt2反之。
在向后合并的时候记一下数,那个数就是答案,


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;


public class Main {
//	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
//	static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
	
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
	
	static int N=100005,n,m;
	
	public static void main(String[] args) throws IOException 
    {
		n=nextInt();m=nextInt();
		int[] a=new int[n+2];
		int[] b=new int[m+2];
		
		for(int i=1;i<=n;i++) a[i]=nextInt();
		for(int j=1;j<=m;j++) b[j]=nextInt();
		
		int cnt1=0,cnt2=0;
		int u=0,v=0;
		int ans=0;
		while(u<=n&&v<=m)
		{
			if(cnt1==cnt2) 
			{
				cnt1=a[++u];
				cnt2=b[++v];
			}
			else if(cnt1>cnt2) 
			{
				cnt2+=b[++v];
				ans++;
			}
			else 
			{
				cnt1+=a[++u];
				ans++;
			}

		}
		
		cout.println(ans);
		cout.flush();
		
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 看清题目要求什么,有时候一些比较难求的东西可以不用求,只要求题目要的答案就行

数三角(几何)

image-20250611233915800

由于数据量比较小,可以先对每个点求出和其他点的距离,放到数组里,方便后面查询

求出来之后,对于每个点都当做顶点来循环,找到两个和它距离一样的点后答案数加1

这里还需要注意共线问题,这里用向量来判断

import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.PriorityQueue;

public class Main {
    static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    static class Point{
        double x,y;
        double[] dis=new double[N];

        public Point(double x, double y) {
            this.x = x;
            this.y = y;
        }

    }
    static double distance(Point a,Point b)
    {
        double disx=a.x-b.x;
        double disy=a.y-b.y;
        return Math.sqrt(disx*disx+disy*disy);
    }
    static boolean check(Point p1,Point p2,Point p3)
    {
        double dx1=p2.x-p1.x,dx2=p3.x-p2.x;
        double dy1=p2.y-p1.y,dy2=p3.y-p2.y;
        if(dx1*dy2==dx2*dy1) return false;
        return true;
    }
    static int INF=0x3f3f3f3f,N=2005,n;
    static Point[] points;
    public static void main(String[] args) throws IOException {
        n=nextInt();
        points=new Point[n+2];
        for (int i = 0; i < n; i++) {
            double x=nextInt(),y=nextInt();
            points[i]=new Point(x,y);
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if(j==i) points[i].dis[j]=0;
                else points[i].dis[j]=distance(points[i],points[j]);
            }
        }

//        for (int i = 0; i < n; i++) {
//            cout.print((i+1)+": ");
//            for (int j = 0; j < n; j++) {
//                cout.print(points[i].dis[j]+" ");
//            }
//            cout.println();
//        }

        int ans=0;
        for(int i=0;i<n;i++)
        {
            Point p=points[i];
            for(int j=0;j<n;j++)
                for(int k=j+1;k<n;k++)
                {
                    if(p.dis[j]==p.dis[k]&&check(points[i],points[j],points[k]))
                    {
//                        cout.println((i+1)+" "+(j+1)+" "+(k+1));
                        ans++;
                    }
                }
        }

        cout.println(ans);
        cout.flush();
    }

    static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    static long nextLong() throws IOException {
        cin.nextToken();
        return (long) cin.nval;
    }
}
  1. 判断共线可以用dx1*dy2==dx2*dy1来判断,如果成立则共线。

删边问题(不会tarjan)

AB路线(BFS)

image-20250612011733200

这里一开始用dfs做的,但是做不出来。

注意这里只要求最短路步数就行,所以用bfs求最短路,直接可以得到步数。

但是要注意对于每个点的状态的定义

import java.io.*;
import java.util.*;

public class Main {
    static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

    static class Pair{
        int x,y,flag;

        public Pair(int x, int y, int flag) {
            this.x = x;
            this.y = y;
            this.flag = flag;
        }
    }
    static int INF=0x3f3f3f3f,N=1005,n,m,k;
    static int[][][] f;
    static int[] dx={0,0,1,-1},dy={1,-1,0,0};
    static char[][] map=new char[N][N];

    static boolean check(int x,int y)
    {
        return x<n&&x>=0&&y<m&&y>=0;
    }

    public static void main(String[] args) throws IOException {
        n=nextInt();m=nextInt();k=nextInt();
        f=new int[n+2][m+2][k+2];

        map=new char[n+2][m+2];
        for(int i=0;i<n;i++)
        {
            String t=nextString();
            map[i]=t.toCharArray();
        }

        Queue<Pair> qu=new ArrayDeque<>();
        qu.offer(new Pair(0,0,1));
        int[][] d={{0,1},{0,-1},{1,0},{-1,0}};
        boolean[][][] vis=new boolean[n][m][2*k];
        for(int step=0;!qu.isEmpty();step++)
        {
            int num= qu.size();
            for(int i=0;i<num;i++)
            {
                Pair pair=qu.poll();
                int px=pair.x,py=pair.y,pf=pair.flag;
                if(vis[px][py][pf]) continue;
                vis[px][py][pf]=true;
                if(pair.x==n-1&&pair.y==m-1)
                {
                    cout.println(step);
                    cout.flush();
                    return;
                }
                for(int j=0;j<4;j++)
                {
                    int x=px+d[j][0];
                    int y=py+d[j][1];
                    int f=(pf+1)%(2*k);
                    if(check(x,y))
                    {
                        if(vis[x][y][f]) continue;
                        if(pf<k&&map[x][y]=='A'||pf>=k&&map[x][y]=='B')
                        {
                            qu.offer(new Pair(x,y,f));
                        }
                    }
                }
            }
        }

//        for(int i=0;i<n;i++)
//        {
//            for(int j=m-1;j>=0;j--)
//            {
//                map[i][j]=map[i][j-1];
//            }
//        }


        cout.println(-1);

        cout.flush();
    }

    static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    static long nextLong() throws IOException {
        cin.nextToken();
        return (long) cin.nval;
    }
    static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
}

抓娃娃(前缀和差分判断区间点的数量)

image-20250612134253473

这里只需要判断线段的中点是否在区间之内就能判断是否符合。同时这里只需要判断数量即可,所以可以利用前缀和,求0~i之内的中点的数量,sum[i],然后用区间进行差分sum[L]-sum[R-1],即可得到区间的数量。

需要注意这里由于是求中点,所以会有小数的情况,我们把所有区间都乘2就不会有小数了

import java.io.*;
import java.util.*;

public class Main {
    static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    static class Range{
        double l,r;
        double mid;
        public Range(double l, double r) {
            this.l = l;
            this.r = r;
            this.mid=(l+r)/2;
        }
    }
    static boolean check(Range o,Range O)//o是否在O里面
    {
        if(o.l<O.l&&o.mid>=O.l) return true;
        if(o.l>=O.l&&o.r<=O.r) return true;
        if(o.r>O.r&&o.mid<=O.r) return true;
        return false;
    }
    static int n,m,N=1000005;
    static int[] sum=new int[2*N];
    static Range[] r1,r2;
    public static void main(String[] args) throws IOException {
        n=nextInt();m=nextInt();
        for(int i=0;i<n;i++)
        {
            int l=nextInt(),r=nextInt();
            sum[l+r]++;
        }
        for(int i=1;i<N*2;i++) sum[i]+=sum[i-1];
        for(int i=0;i<m;i++)
        {
            int L=nextInt(),R=nextInt();
            cout.println(sum[2*R]-sum[2*L-1]);
        }

        cout.flush();
    }

    static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    static long nextLong() throws IOException {
        cin.nextToken();
        return (long) cin.nval;
    }
    static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
}
  1. 求区间中点的数量可以用前缀和处理,然后用差分得到答案

拼数字(不会,跳)

逃跑(不会,跳)

14届python B

弹珠堆放(暴力)

image-20250612232008068

每一层的个数是\(1+2+3+...+n=(n+1)n/2\)

import java.io.*;
import java.util.*;

public class Main {
    static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

    public static void main(String[] args) throws IOException {
        int cnt=0;
        int i=1;
        while(true)
        {
            cnt+=(i+1)*i/2;
            cout.println(i+":"+cnt);
            if(cnt>20230610) break;
            i++;
        }
        
        cout.println(i-1);
        cout.flush();
    }

    static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    static long nextLong() throws IOException {
        cin.nextToken();
        return (long) cin.nval;
    }
    static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
}

划分(01背包划分集合尽量相等)

image-20250613000134606

由基本不等式可以知道,两个数如果相等的话是最大值。那么就求这个集合里最相近的两个数就行了。

在背包问题中求dp[i][j]时,得到的是离j最近的数,所以可以用01背包求小于sum/2的值,另外一个大于sum/2的值就得到了,相乘就是答案。

import java.io.*;
import java.util.*;

public class Main {
    static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

    public static void main(String[] args) throws IOException {
//        int[] arr={
//                5160,9191,6410,4657,7492,1531,8854,1253,4520,9231,
//                1266,4801,3484,4323,5070 ,1789 ,2744 ,5959,9426 ,4433,
//                4404, 5291, 2470 ,8533, 7608 ,2935 ,8922 ,5273 ,8364, 8819,
//                7374, 8077 ,5336 ,8495 ,5602 ,6553 ,3548 ,5267 ,9150 ,3309};
//        int sum=226924;
//
//        long[] dp=new long[sum+1];
//        for(int i=0;i<arr.length;i++)
//            for(int j=sum;j>=arr[i];j--)
//                dp[j]=Math.max(dp[j],dp[j-arr[i]]+arr[i]);
//        cout.println(dp[sum/2]*(sum-dp[sum/2]));
//        System.out.println();
//        cout.flush();
        System.out.println(12873625444L);
    }

    static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    static long nextLong() throws IOException {
        cin.nextToken();
        return (long) cin.nval;
    }
    static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
}

偶串(哈希表)

image-20250613001149139

直接用哈希表记录字符串和出现的次数就行

import java.io.*;
import java.util.*;

public class Main {
    static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

    public static void main(String[] args) throws IOException {
        HashMap<Character,Integer> hash=new HashMap<>();
        char[] str=nextString().toCharArray();
        for(char t:str)
        {
            hash.put(t,hash.getOrDefault(t,0)+1);
        }
        boolean flag=false;
        for(Integer t:hash.values())
        {
            if(t%2!=0) flag=true;
        }
        if(flag) cout.println("NO");
        else cout.println("YES");

        cout.flush();
    }

    static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    static long nextLong() throws IOException {
        cin.nextToken();
        return (long) cin.nval;
    }
    static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
}

-------------------------

15届JAVA B

类斐波那契循环数(把数变成字符串再取每一位。用栈记录总合中的数字组成)

import java.util.*;
public class Main {
    static int N = 1100, INF = 0x3f3f3f3f;
    public static int sumDigits(int[] arr)
    {
        int sum=0;
        for(int num:arr)
        {
            sum+=num;
        }
        return sum;
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
//        int n=scan.nextInt();

        for (int i = (int)1e7; i>0; i--) {
//            System.out.println(i);
            String str=Integer.toString(i);
            int size=str.length();
            int[] num = new int[size];
            for(int j=0;j<size;j++)
            {
                num[j]=str.charAt(j)-'0';
//                System.out.println(num[j]);
            }
            int sum = 0;
            Deque<Integer> queue=new ArrayDeque<>();
            for(int d:num)
            {
//                System.out.println(d);
                queue.addLast(d);
            }
            sum=sumDigits(num);
            if(sum==i)
            {
                System.out.println(i);
                return;
            }
            if(sum>i)
            {
                break;
            }
            while (true)
            {
                int next=sum;
                if(queue.size()>=size)
                {
                    sum-=queue.removeFirst();
                }
                queue.addLast(next);
                sum+=next;
                if(sum==i){
                    System.out.println(i);
                    return;
                }
                if(sum>i)
                {
                    break;
                }
            }

        }
    }
}
  1. Integer.toString(i);str.charAt(j)-'0';来正着取一个数的每一位
  2. 队列Deque<Integer> queue=new ArrayDeque<>();

分布式队列(模拟,但是有的地方不需要模拟)

image-20250404091928232

import java.util.*;
public class Main {
    static int N = 105, INF = 0x3f3f3f3f;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n=scan.nextInt();
//        int[][] node=new int[n][N];
        int[] station=new int[n];
        int minst=0;
        String cmd= "";
        while (scan.hasNext())
        {
            cmd=scan.next();
            if(cmd.equals("add"))
            {
//                System.out.println("add");
                int element=scan.nextInt();
//                System.out.println(element);
//                node[0][station[0]]=element;
                station[0]++;
            }
            if(cmd.equals("sync"))
            {
                int follower=scan.nextInt();
                if(station[follower]<station[0])
                {
//                    node[follower][station[follower]]=node[follower][station[follower]];
                    station[follower]++;
                }
            }
            if(cmd.equals("query"))
            {
                minst=station[0];
                for(int i=1;i<n;i++)
                {
                    minst=Math.min(station[i],minst);
                }
                System.out.println(minst);
            }
        }
    }
}
  1. 模拟的时候可以不用全部模拟,看答案需求,有的地方不需要模拟也可以输出正确答案
  2. scan.hasNext()来表示有没有下一个输入

食堂(大模拟,分类讨论。用while循环一个一个检查,不要除和取余直接求)

image-20250404143553538

import java.util.*;
public class Main {
    static int N = 105, INF = 0x3f3f3f3f;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int q=scan.nextInt();
        while ((q--)!=0)
        {
            int a2,a3,a4,b4,b6,sum=0;
            a2=scan.nextInt();
            a3=scan.nextInt();
            a4=scan.nextInt();
            b4=scan.nextInt();
            b6=scan.nextInt();
            while(a4*4>=4&&b4>0)//4*1=4
            {
                a4-=1;b4-=1;sum+=4;
            }
            while(a2*2>=4&&b4>0) //2*2=4
            {
                a2-=2;b4-=1;sum+=4;
            }
            while (a2*2>=2&&a4*4>=4&&b6>0)//2+4=6
            {
                a2-=1;a4-=1;b6-=1;sum+=6;
            }
            while (a2*2>=6&&b6>0)//2*3=6
            {
                a2-=3;b6-=1;sum+=6;
            }
            while(a3*3>=6&&b6>0)//3*2=6
            {
                a3-=2;b6-=1;sum+=6;
            }
            while (a3*3>=3&&b4>0)//余1:3=3
            {
                a3-=1;b4-=1;sum+=3;
            }
            while (a3*3>=3&&a2*2>=2&&b6>0)//余1:2+3=5
            {
                a3-=1;a2-=1;b6-=1;sum+=5;
            }
            while (a4*4>=4&&b6>0)//余2:4=4
            {
                a4-=1;b6-=1;sum+=4;
            }
            while (a2*2>=4&&b6>0)//余2:2*2=4
            {
                a2-=2;b6-=1;sum+=4;
            }
            while (a2*2>=2&&b4>0)//余2:2=2
            {
                a2-=1;b4-=1;sum+=2;
            }
            while (a3*3>=3&&b6>0)//余3:3=3
            {
                a3-=1;b6-=1;sum+=3;
            }
            while (a2*2>=2&&b6>0)//余4:2=2
            {
                a2-=1;b6-=1;sum+=2;
            }
//            System.out.println(a2+" "+a3+" "+a4+" "+b4+" "+b6+" ");
//            sum+=(b4*4+b6*6);
            System.out.println(sum);
        }
    }
}
  1. 枚举的时候不要用/%来枚举,不要一口气完成。用while循环来枚举
  2. 分类讨论的时候按顺序来,不要怕这种大模拟
  3. 这题优先枚举4人桌,再枚举6人桌。先枚举整个的,再枚举缺的
  4. 这题的答案是在满足条件的情况下尽可能多的人在食堂,不能超过总人数

最优分组(高中生物)

image-20250404151422424

一组K只宠物,那么没有宠物感染的概率就是P=(1-p)^K,至少有一只宠物感染的概率即1-P,对于对于一共N/K组,自然即有P*N/K组未感染,(1-P)*N/K组感染,未感染的话只需1只药剂,否则需要(1+K)支药剂(K==1时除外)(官解的公式里写成1*K了,但是代码是对的,结果我看半天不知道为什么),那么用药数量就是E=(P+(1-P)(K+1))N/K了,对于N是否能正好分成K份,因为数据小直接暴力就完事

import java.util.*;
public class Main {
    static int N = 105, INF = 0x3f3f3f3f;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n= scan.nextInt();
        double p=scan.nextDouble();
        int minK=Integer.MAX_VALUE;
        double minE=Double.MAX_VALUE;
        for(int K=n;K>=1;K--)
        {
            if(n%K==0)
            {
                double P=Math.pow(1-p,K);
                double E=(P+(1-P)*(K+1))*N/K;
                if(K==1) K=N;
                if(E<minE)
                {
                    minK=K;
                    minE=E;
                }
            }
        }
        System.out.println(minK);
    }
}
  1. 碰到实际的问题也可以实际上去想,这里就用到了高中生物概率题里的常见思维
  2. 需要注意这题K=1的时候K=N,不能套用公式,因为这个时候公式为0。

星际旅行(folyd求最短路)

1.星际旅行 - 蓝桥云课

image-20250405111731769

import java.util.*;
public class Main {
    static int N=220,INF=0x3f3f3f3f,n,m,q,sum;
//    static int[][] g=new int[N][N];

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        n= scan.nextInt();
        m= scan.nextInt();
        q= scan.nextInt();
        int[][] g=new int[n+1][n+1];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                if(i==j) g[i][j]=0;
                else g[i][j]=INF;
//                g[i][j]=INF;
            }
        while (m-- > 0)
        {
            int a= scan.nextInt();
            int b=scan.nextInt();
            g[a][b]=g[b][a]=1;
        }
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    g[i][j]=Math.min(g[i][j],g[i][k]+g[k][j]);
        int t=q;
        while (t-- > 0)
        {
            int x= scan.nextInt();
            int y=scan.nextInt();
            for(int i=1;i<=n;i++)
            {
                if(g[x][i]<=y) sum++;
            }
        }
        System.out.printf("%.2f",(double)sum/q);
    }
}
  1. java中可以不用一开始就新建数组,可以在得到数组长度后再新建
  2. 要看清输出格式的要求,是整数还是浮点数,要保留几位小数
  3. java中的如果要保留两位小数就要用System.out.printf("%.2f",(double)sum/q);

LITS游戏(程序画图枚举)

image-20250405123010139

import java.util.*;
public class Main {
    static int[][][][] pl={
            {
                    {{0,0},{1,0},{2,0},{2,1}}, //0
                    {{0,0},{1,0},{0,1},{0,2}},//90
                    {{0,0},{0,1},{1,1},{2,1}},//180
                    {{1,0},{1,1},{1,2},{0,2}}//270
            },
            {
                    {{0,0},{1,0},{2,0},{3,0}},
                    {{0,0},{0,1},{0,2},{0,3}}
            },
            {
                    {{0,0},{0,1},{0,2},{1,1}},//0
                    {{1,0},{0,1},{1,1},{2,2}},//90
                    {{1,0},{1,1},{0,1},{1,2}},//180
                    {{0,0},{1,0},{2,0},{1,1}}//270
            },
            {
                    {{1,0},{0,1},{1,1},{0,2}},
                    {{0,0},{1,0},{1,1},{2,1}}
            }
    };
    static int N=55,INF=0x3f3f3f3f,t,n;
    static int[][] g=new int[N][N];
    static boolean success;
    static boolean inBound(int x,int y)
    {
        return x>=1&&x<=n&&y>=1&&y<=n;
    }
    static boolean canPlace(int type,int chosen,int startX,int startY)
    {
        for(int[] pos:pl[type][chosen]){
            int x=startX+pos[0],y=startY+pos[1];
            if(!inBound(x,y)||g[x][y]!=1) return false;
        }
        return true;
    }
    static void draw(int type,int chosen,int startX,int startY,int target)
    {
        for(int[] pos:pl[type][chosen]) g[startX+pos[0]][startY+pos[1]]=target;
    }
    static void choosePlan(int now)
    {
        if(success) return;
        if(now==4) success=true;
        else for(int i=0;i<pl[now].length;i++)
        {
            if(success) return;
            for(int x=1;x<=n;x++)
            {
                for(int y=1;y<=n;y++)
                {
                    if(!canPlace(now,i,x,y)) continue;
                    draw(now,i,x,y,2);
                    choosePlan(now+1);
                    draw(now,i,x,y,1);
                }
            }
        }
    }
    static boolean solve(){
        success=false;
        choosePlan(0);
        return success;
    }
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        t=scan.nextInt();
        while (t-- > 0)
        {
            n=scan.nextInt();
//            success=false;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    g[i][j]=scan.nextInt();
                }
            }
            System.out.println(solve()?"Yes":"No");
        }
    }
}
  1. 通过枚举每个位置上的图形来得到答案

15届pythonB

连连看(几何特征减少复杂度)

image-20250407134605270

暴力代码:过50%

import java.io.*;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;

public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));

    static int N=(int)1e3+4,n,m,ans;
    static int[][] g=new int[N][N];

    public static void main(String[] args) throws IOException {
        n=nextInt();m=nextInt();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                g[i][j]=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++)
                        if(i!=k && j!=l && g[i][j]==g[k][l] && Math.abs(i-k)==Math.abs(j-l) && Math.abs(i-k)>0)
                            ans++;
        cout.println(ans);
        cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll()
    {
        cout.close();
    }
}

通过几何特征:如果要满足|a-c|=|b-d|>0,那么只有右上45度,右下45度,左上45度,左下45度符合要求。可以将复杂度减少到O(n^3)

import java.io.*;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;

public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));

    static int N=(int)1e3+4,n,m,ans;
    static int[][] g=new int[N][N];

//    static int check(int )
    static boolean check(int x,int y)
    {
        return x>=1&&x<=n&&y>=1&&y<=m;
    }

    public static void main(String[] args) throws IOException {
        n=nextInt();m=nextInt();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                g[i][j]=nextInt();

        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                for(int k=1;check(i-k,j+k);k++) //右上
                {
                    if(g[i][j]==g[i-k][j+k]) ans++;
                }
                for(int k=1;check(i+k,j+k);k++) //右下
                {
                    if(g[i][j]==g[i+k][j+k]) ans++;
                }
                for(int k=1;check(i-k,j-k);k++) //左上
                {
                    if(g[i][j]==g[i-k][j-k]) ans++;
                }
                for(int k=1;check(i+k,j-k);k++) //左下
                {
                    if(g[i][j]==g[i+k][j-k]) ans++;
                }
            }
//        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++)
//                        if(i!=k && j!=l && g[i][j]==g[k][l] && Math.abs(i-k)==Math.abs(j-l) && Math.abs(i-k)>0)
//                            ans++;
        cout.println(ans);
        cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 有一些题可以通过找一些几何特性来减少复杂度

神奇闹钟(日期问题)

蓝桥村的真相(思维,枚举找规律)

image-20250407132030808image-20250410183639718

这里用暴力的做法来做(过不了几个)

import java.io.*;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;

public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));

    static int N=(int)1e5+4,T,ans;
    static int[] st=new int[N];

    static void dfs(boolean[] g,int idx,int n)
    {
        if(idx==n)
        {
//            for(int i=0;i<n;i++) cout.print(g[i]+" ");
//            cout.println();
            boolean flag=true;
            int cnt=0;
            for(int i=0;i<n;i++)
            {
                if(g[i]&&g[(i+1)%n]==g[(i+2)%n]) flag=false;
                if(!g[i]&&g[(i+1)%n]!=g[(i+2)%n]) flag=false;
                if(!flag) break;
                if(!g[i]) cnt++;
            }
            if(flag)
            {
                ans+=cnt;
//                cout.println("--------------------");
            }
            else
            {
                return;
            }
        }
        if(idx<n)
        {
            g[idx]=true;
            dfs(g,idx+1,n);
            g[idx]=false;
            dfs(g,idx+1,n);
        }
    }

    public static void main(String[] args) throws IOException {
//        int n=nextInt();
        boolean flag=true;
        for(int i=1;i<=50;i++)
        {
            ans=0;
            dfs(new boolean[i+1],0,i);
            cout.println(i+" "+ans);
            cout.flush();
        }


    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 暴力:对于这种一个数组里面的数的排列组合可以用dfs来枚举,一开始没想到dfs
  2. 如果是真,那么后面两个不一样。如果是假,那么后面两个一样。一开始没想到
  3. 对于一些题可以通过枚举来看能不能找到规律

魔法巡游20%(暴力模拟)

image-20250410183833516image-20250410183846325image-20250410183855569

import java.io.*;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;

public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));

    static int N=(int)1e5+4,n,ans;
    static int[] s=new int[N],t=new int[N];
    static int check(int x) //用二进制表示是否有0,2,4。
    {
        int ans=0;
        while (x!=0)
        {
            int t=x%10;
            if(t==0&&(ans&1)==0) ans+=1;
            if(t==2&&(ans&2)==0) ans+=2;
            if(t==4&&((ans&4)==0)) ans+=4;
            x/=10;
        }
        return ans;
    }

    public static void main(String[] args) throws IOException {
        n=nextInt();
        for(int i=1;i<=n;i++)
        {
            s[i]=check(nextInt());
            cout.print(Integer.toBinaryString(s[i])+" ");
        }
        cout.println();
        for(int i=1;i<=n;i++)
        {
            t[i]=check(nextInt());
            cout.print(Integer.toBinaryString(t[i])+" ");
        }
        cout.println();
        boolean flag=false;//true表示下一个是小蓝,false表示下一个是小桥
        int x,last;
        for(x=1;s[x]==0&&x<=n;x++);//小蓝先走
        cout.println(x+" "+Integer.toBinaryString(s[x]));
        last=s[x];x++;ans++;
        while (x<=n)
        {
            if(flag)
            {
                while (x<=n&&(last&s[x])==0) x++;
                if(x>n) break;
                cout.println(x+" "+Integer.toBinaryString(s[x]));
                last=s[x];ans++;x++;
                flag=false;
            }
            else
            {
                while (x<=n&&(last&t[x])==0) x++;
                if(x>n) break;
                cout.println(x+" "+Integer.toBinaryString(t[x]));
                last=t[x];ans++;x++;
                flag=true;
            }
        }
        cout.println(ans);

        cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 这题因为审题被坑了,一开始以为不用两个一样的就可以。在做题前要仔细审查每一个情况

纯职业小组(不会)

15届C B

数字接龙(dfs)

image-20250407173337195image-20250407173346150

import java.io.*;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;

public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static int N=12,cnt,n,k;
    static int[][] g=new int[N][N];
    static int[] dx={-1,-1,0,1,1,1,0,-1},dy={0,1,1,1,0,-1,-1,-1};
    static int[] ans=new int[102],ans1=new int[102];
    static boolean[][] st=new boolean[N][N];
    static boolean[][][][] edge=new boolean[N][N][N][N];
    static boolean check(int x,int y)
    {
        return x>=0&&x<n&&y>=0&&y<n&&!st[x][y];
    }
    static void dfs(int x,int y,int idx)
    {
        if(x==n-1&&y==n-1&&idx==cnt)
        {
//            for(int i=0;i<cnt;i++) cout.print(ans1[i]);
//            cout.println();
            boolean flag=false;
            for(int i=0;i<cnt;i++)
            {
                if(ans1[i]<ans[i])
                {
                    flag=true;
                    break;
                }
                if(ans1[i]>ans[i]) break;
            }
            if(flag)
            {
                for(int i=0;i<cnt;i++) ans[i]=ans1[i];
            }
        }
        for(int i=0;i<8;i++)
        {
            int nx=x+dx[i],ny=y+dy[i];
            if(check(nx,ny)&&(g[x][y]+1)%k==g[nx][ny])
            {
                if(i%2==1&&(edge[nx][y][x][ny]||edge[x][ny][nx][y])) continue;

                if(i%2==1) edge[x][y][nx][ny]=true;
                ans1[idx]=i;st[nx][ny]=true;
                dfs(nx,ny,idx+1);
                if(i%2==1) edge[x][y][nx][ny]=false;
                ans1[idx]=0;st[nx][ny]=false;
            }
        }
    }

    public static void main(String[] args) throws IOException {
        n=nextInt();
        k=nextInt();
        cnt=n*n-1;
        st[0][0]=true;
        for(int i=0;i<cnt;i++) ans[i]=9;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                g[i][j]=nextInt();
        dfs(0,0,0);
        for(int i=0;i<cnt;i++) cout.print(ans[i]);

        cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 没想到用edge[][][][]表示斜走有没有交叉,其他倒是都想到了

14届C B

日期统计(子序列,暴力)

image-20250409002452546

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	
	static int[] num= {5,6,8,6,9,1,6,1,2,4,9,1,9,8,2,3,6,4,7,7,
			5,9,5,0,3,8,7,5,8,1,5,8,6,1,8,3,0,3,7,9,2,7,
			0,5,8,8,5,7,0,9,9,1,9,4,4,6,8,6,3,3,8,5,1,6,
			3,4,6,7,0,7,8,2,7,6,8,9,5,6,5,6,1,4,0,1,0,0,
			9,4,8,0,9,1,2,8,5,0,2,5,3,3};
	static int[] month_day= {0,31,28,31,30,31,30,31,31,30,31,30,31};
	
    public static void main(String[] args) throws IOException {
    	int[] date= {0,2,0,2,3,0,0,0,0,0};
    	int ans=0;
    	for(int i=1;i<=12;i++)
    	{
    		date[5]=i/10;date[6]=i%10;
    		int day=month_day[i];
    		for(int j=1;j<=day;j++)
    		{
    			date[7]=j/10;date[8]=j%10;
    			int k=1;
        		for(int t:num)
        		{
        			if(t==date[k]) k++;
        			if(k>8)
        			{
        				ans++;
        				break;
        			}
        		}
    		}
    		
    		
//    		for(int j=1;j<=8;j++) cout.print(date[j]);
//    		cout.println();
//    		for(int t:num)
//    		{
//    			if(t==date[k]) k++;
//    			if(k>8)
//    			{
//    				ans++;
//    				break;
//    			}
//    		}
    	}
    	cout.print(ans);
    	cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 没理解子序列的意思。
    子序列是指从一个序列(如数组、字符串等)中按顺序选取若干元素(可以不连续),但保持原始顺序的新序列。
    与子串(Substring)不同,子序列不要求元素在原序列中连续。

冶炼金属(数学)

image-20250410163521204image-20250410163529679

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));

	
    public static void main(String[] args) throws IOException {
    	int n=nextInt();
    	int min=Integer.MIN_VALUE,max=Integer.MAX_VALUE;
    	for(int i=0;i<n;i++)
    	{
    		int a=nextInt();
    		int b=nextInt();
    		min=Math.max(min, (a/(b+1))+1);
    		max=Math.min(max,(a/b));
    	}
    	cout.print(min+" "+max);
    	cout.flush();
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}

飞机降落(dfs暴力枚举)

image-20250410170442285

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static int N=12,n;
	static int[][] arr=new int[N][3];//0:T 1:D 2:L
	static boolean[] st=new boolean[N];
	static boolean flag;
	
	static void dfs(int cnt,int last)
	{
		if(cnt==n)
		{
			flag=true;
			return;
		}
		for(int i=0;i<n;i++)
		{
			if(!st[i]&&arr[i][0]+arr[i][1]>=last)
			{
				st[i]=true;
				dfs(cnt+1,Math.max(arr[i][0],last)+arr[i][2]);
				st[i]=false;
			}
			if(flag) return;
		}
	}
	
    public static void main(String[] args) throws IOException {
    	int T=nextInt();
    	while(T-- > 0)
    	{
    		n=nextInt();
    		flag=false;
    		for(int i=0;i<n;i++)
    		{
    			arr[i][0]=nextInt();
    			arr[i][1]=nextInt();
    			arr[i][2]=nextInt();
    		}
    		dfs(0,0);
    		if(flag) cout.println("YES");
    		else cout.println("NO");
    	}
    	cout.flush();
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}

14届JAVA B

阶乘求和

image-20250405195119357

幸运数字

image-20250405194752553

import javax.swing.*;
import java.util.*;
public class Main {
    static int N=(int)5e5+4,n,ans;

    static boolean check(int x)
    {
        int sum=0;
        String bin=Integer.toBinaryString(x);
        String oct=Integer.toOctalString(x);
        String ten=Integer.toString(x);
        String hex=Integer.toHexString(x);
        int[] bins=new int[N],octs=new int[N],tens=new int[N],hexs=new int[N];

        for(int i=0;i<bin.length();i++)
        {
            bins[i]=(int)(bin.charAt(i)-'0');
            sum+=bins[i];
        }
        if(x%sum!=0) return false;

        sum=0;
        for(int i=0;i<oct.length();i++)
        {
            octs[i]=(int)(oct.charAt(i)-'0');
            sum+=octs[i];
        }
        if(x%sum!=0) return false;

        sum=0;
        for(int i=0;i<ten.length();i++)
        {
            tens[i]=(int)(ten.charAt(i)-'0');
            sum+=tens[i];
        }
        if(x%sum!=0) return false;

        sum=0;
        for(int i=0;i<hex.length();i++)
        {
            if(hex.charAt(i)=='a') hexs[i]=10;
            else if(hex.charAt(i)=='b') hexs[i]=11;
            else if(hex.charAt(i)=='c') hexs[i]=12;
            else if(hex.charAt(i)=='d') hexs[i]=13;
            else if(hex.charAt(i)=='e') hexs[i]=14;
            else if(hex.charAt(i)=='f') hexs[i]=15;
            else {
                hexs[i]=(int)(hex.charAt(i)-'0');
            }
        }
        for(int i=0;i<hex.length();i++) sum+=hexs[i];
        if(x%sum!=0) return false;

        return true;
    }

    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        n=1;
        while (ans!=2023)
        {
            if(check(n))
            {
                ans++;
                System.out.println(n+" "+ans);
            }
            n++;
        }
        System.out.println(n-1);
    }
}
  1. 题目里举例子了一定要用到这个测试集来测试程序

数组分割

image-20250405215023777image-20250410185211133image-20250410185217260

import javax.swing.*;
import java.io.*;
import java.util.*;
public class Main {

    static int N=(int)1e3+4,MOD=1000000007,t,n;

    public static void main(String[] args) throws IOException {
        StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
        cin.nextToken();t=(int)cin.nval;
        while (t-- > 0)
        {
            cin.nextToken();n=(int)cin.nval;
//            int[] num=new int[n];
            int onum=0;
            int snum=0;
            int t=0;
            int ans=0;
            for(int i=1;i<=n;i++)
            {
                cin.nextToken();t=(int)cin.nval;
                if((t&1)==1) onum=(onum+1)%MOD;
                else snum=(snum+1)%MOD;
            }
            if((onum&1)==1)
            {
                cout.println("0");
                cout.flush();
                continue;
            }
//            onum/=2;
//            sum=(onum+snum)%MOD;
//            cout.println(sum);cout.flush();
            if(onum!=0)
            {
                ans=(int)(Math.pow(2,n-1)%MOD);
                cout.println(ans);
                cout.flush();
            }
            else
            {
                ans=(int)(Math.pow(2,n)%MOD);
                cout.println(ans);
                cout.flush();
            }

        }
    }
}
  1. 一开始没理解对,当成了把奇数两个分组,所以出现了onum/2,但是没想到这样做是强行两两分组,而且不能拆开
  2. 分清楚是子序列还是子集,一个要求有序,一个无序

矩形总面积(计算几何)

image-20250406095122051

import javax.swing.*;
import java.io.*;
import java.util.*;
public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
//    static int x1,x2,y1,y2,x3,x4,y3,y4;
    static int ans=0;

    public static int Area(int x1,int x2,int y1,int y2)
    {
        return Math.abs((x1-x2)*(y1-y2));
    }
    public static void main(String[] args) throws IOException {
        int x1,x2,y1,y2,x3,x4,y3,y4;
        x1=nextInt();y1=nextInt();x2=nextInt();y2=nextInt();
        x3=nextInt();y3=nextInt();x4=nextInt();y4=nextInt();
//        int ans=0;
        ans=Area(x1,x2,y1,y2)+Area(x3,x4,y3,y4);
        int x=Math.abs(Math.min(x2,x4)-Math.max(x1,x3));
        int y=Math.abs(Math.min(y2,y4)-Math.max(y1,y3));
        if(x>0&&y>0) ans-=x*y;
        cout.println(ans);
        cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 重叠区域的面积:在x轴上的重叠长度为:Math.abs(Math.min(x2,x4)-Math.max(x1,x3)),同理,在y轴上重叠长度为Math.abs(Math.min(y2,y4)-Math.max(y1,y3))

蜗牛(简单的动态规划)

image-20250406122430679

  1. 状态表示f[i][0]f[i][1]:

    • 集合:f[i][0]到达第i个结点的集合。f[i][1]到达第i个传送门的集合
    • 属性:min
  2. 状态计算:

    •     `f[i][0]=Math.min(dp(i-1,0)+x[i]-x[i-1],dp(i-1,1)+b[i]/1.3);`
          
          `f[i][1]=Math.min(dp(i-1,0)+(x[i]-x[i-1])+a[i]/0.7,dp(i-1,1)+(b[i]>a[i] ? (b[i]-a[i])/1.3 : (a[i]-b[i])/0.7 ));`
      
import java.io.*;
import java.util.*;
public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
    static int N=(int)1e5+4,n,i=0;
    static int[] x=new int[N];
    static double t;
    static double[] a=new double[N],b=new double[N];
    static double[][] f=new double[N][2];
    static double dp(int i,int st)
    {
        if(f[i][st]!=0) return f[i][st];
        f[i][0]=Math.min(dp(i-1,0)+x[i]-x[i-1],dp(i-1,1)+b[i]/1.3);
        f[i][1]=Math.min(dp(i-1,0)+(x[i]-x[i-1])+a[i]/0.7,dp(i-1,1)+(b[i]>a[i] ? (b[i]-a[i])/1.3 : (a[i]-b[i])/0.7 ));
        return f[i][st];
    }

    public static void main(String[] args) throws IOException {
        n=nextInt();
        for(int i=1;i<=n;i++)
        {
            x[i]=nextInt();
        }
        for(int i=1;i<=n-1;i++)
        {
            a[i]=nextDouble();
            b[i+1]=nextDouble();
        }

        f[1][0]=x[1];
        f[1][1]=x[1]+a[1]/0.7;

        double ans=dp(n,0);
        cout.printf("%.2f",ans);
        cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 好长时间没做dp,没想到dp,一开始用的大模拟,写了两个小时也没写出来,看wp才知道是dp,这个形式确实是一个很简单的dp

买二赠一70%(贪心,队列)

image-20250406164440997image-20250406164448939

import java.io.*;
import java.util.*;
public class Main {
    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));

    static int N=(int)5e5+3,n,ans;
    static int[] a=new int[N];

    public static void main(String[] args) throws IOException {
        n=nextInt();
        for(int i=1;i<=n;i++)
        {
            a[i]=nextInt();
//            cout.println(i+" "+a[i]);
        }
        Arrays.sort(a,1,1+n);
//        for(int i=1;i<=n;i++) cout.println(i+" "+a[i]);

        Deque<Integer> queue=new ArrayDeque<>();
        int cnt=0;
        for(int i=n;i>0;i--)
        {
//            cout.println(i+" "+a[i]);
            if(!queue.isEmpty()&&queue.getFirst()>=a[i])
            {
                queue.removeFirst();
                continue;
            }
            cnt++;ans+=a[i];
            if((cnt&1)==0) queue.addLast(a[i]/2);
        }
        cout.println(ans);
        cout.flush();
    }


    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval;
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 一开始想到贪心没敢用,不知道怎么证明,到最后也没写。
  2. 以后想到贪心,如果证明不出来也没事,先写了再说,可以看后面的题。

合并石子(区间dp)

最大开支(数学函数,贪心,优先队列)

image-20250410201327446image-20250410201358272image-20250410201416438image-20250410201423452

暴力:过30%

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	
	static int N=(int)1e5+5,n,m,ans,sum;
	static int[] k=new int[N],b=new int[N],x0=new int[N];
	static int[][] t=new int[N][2];
	
	static void dfs(int now,int scnt)
	{
		if(now==m)
		{
			ans=Math.max(ans,sum);
//			for(int i=0;i<m;i++) cout.print(t[i][0]+" ");
//			cout.println();
//			for(int i=0;i<m;i++) cout.print(t[i][1]+" ");
//			cout.println();
//			cout.println(ans+" "+sum);
//			cout.println("------------------------");
			return;
		}
		for(int i=0;i<=scnt;i++)
		{
			sum+=i*Math.max(k[now]*i+b[now],0);
			t[now][0]=i;t[now][1]=i*Math.max(k[now]*i+b[now],0);
			dfs(now+1,scnt-i);
			sum-=i*Math.max(k[now]*i+b[now],0);
		}
			
	}
	
    public static void main(String[] args) throws IOException {
    	n=nextInt();
    	m=nextInt();
    	for(int i=0;i<m;i++)
    	{
    		k[i]=nextInt();
    		b[i]=nextInt();    	
    	}
    	dfs(0,n);
    	cout.println(ans);
    	cout.flush();
    	
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}

正确做法

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayDeque;
import java.util.Comparator;
import java.util.Deque;
import java.util.PriorityQueue;

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	
    public static void main(String[] args) throws IOException {
    	int k,b,n=nextInt(),m=nextInt();
    	Comparator<Integer> cp=(o1,o2)-> o2-o1;
    	PriorityQueue<Integer> pq=new PriorityQueue<Integer>(cp);
    	Deque<Integer> deque=new ArrayDeque<Integer>();
    	deque.removeFirst()
    	for(int i=1;i<=m;i++)
    	{
    		k=nextInt();b=nextInt();
    		for(int j=1;j<=n;j++)
    		{
    			int cost=2*k*j-k+b;
    			if(cost>0)
    			{
    				pq.add(cost);
    			}
    			else 
    			{
					break;
				}
    		}
    	}
    	long maxCost=0;
    	int num=Math.min(n,pq.size());
    	for(int j=0;j<num;j++)
    	{
    		maxCost+=pq.poll();
    	}
    	cout.print(maxCost);
    	cout.flush();
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 通过函数关系找到每一个项目增加一个人增加的钱cost=2*k*j-k+b;,然后枚举每一个项目到第几个人cost为负,就退出。把每一个cost为正的放入优先队列,由二次函数的性质可以知道,cost最大的一定是人最少的。所以可以放心的取优先队列的第一个数,人数一定是递增的

14届Python B

2023

image-20250411192649030

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	
	static boolean check(int x) //有2023返回true
	{
		char[] t=Integer.toString(x).toCharArray();
		boolean flag;
		int[] num= {2,0,2,3,0};
		int j=0;
		for(char c:t)
		{
			if(j==4) break;
			if(c==num[j]+'0') j++;
		}
		if(j==4) return true;
		return false;
	}
	
    public static void main(String[] args) throws IOException 
    {
    	int cnt=0;
//    	cout.println(check(20322175));
//    	cout.println(check(33220022));
//    	cout.println(check(20230415));
//    	cout.println(check(20193213));
//    	cout.println(check(20020023));
    	for(int i=12345678;i<=98765432;i++)
    	{
    		if(!check(i)) cnt++;
    	}
    	cout.print(cnt);
    	cout.flush();
    	System.out.println();
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
  1. 写这种大数字的时候要注意。我写循环的时候写成了1234567不是12345678,难绷。

硬币兑换

package lqb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
//    public static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//    public static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer cin=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter cout=new PrintWriter(new OutputStreamWriter(System.out));
	
	
    public static void main(String[] args) throws IOException 
    {
    	int[] arr=new int[10000];
    	for(int i=1;i<=2023;i++) arr[i]=i;
    	
    	int res=0;
    	int ans=Integer.MIN_VALUE;
    	for(int i=1;i<=4046;i++)
    	{
    		res=0;
    		for(int j=1;j<=i/2;j++)
    		{
    			int k=i-j;
    			if(k!=j) {
    				res+=Math.min(arr[k],arr[j]);
    			}else {
    				res+=arr[k]/2;
    			}
    		}
    		res+=arr[i];
    		ans=Math.max(ans,res);
    	}
    	cout.print(ans);
    	cout.flush();
    }
    

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int)cin.nval;
    }
    public static long nextLong() throws IOException {
        cin.nextToken();
        return (long)cin.nval;
    }
    public static double nextDouble() throws IOException {
        cin.nextToken();
        return cin.nval;
    }
    public static String nextString() throws IOException {
        cin.nextToken();
        return cin.sval; 
    }
    public static void closeAll()
    {
        cout.close();
    }
}
posted @ 2025-04-08 18:37  r_0xy  阅读(42)  评论(0)    收藏  举报