今天早上9.20-现在(2023年4月6日20:42:35),总结了蓝桥杯部分考点和这一个多月来的努力,从连素数都不会的小白变成了简单dfs能写出来的"大神",真后悔大二下才开始搞算法,不知道浪费了多少时间,害!
还是回想起她,在每个夜晚,心里会不自觉的想起她,她的面容浮现在我的脑海,她的声音缭绕在我的耳旁,不知为何,突然怎么想她,可能是这段时间内心太寂寞了,果然打代码是最不需要女人的,女人会影响速度,不只是打代码方面的速度,决定打完比赛就和她联系吧,如果她拒绝,就祝她过得更好,她答应我也会对她更好的,我想你了!
题目的数据范围决定了变量的数据类型
快读: BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
读数据:long n = Long.parseLong(in.readLine());
快写: PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
out.print(n);
out.flush();
1.搜索
spfa(路径)
求单源起点到任意点的距离,图的权值有题目决定
设置中间节点和距离
简单的dfs(灌溉,长草,扫雷,受伤的皇后)
板子题
难一点的dfs(全球变暖,滑雪,剪格子)
滑雪:dp数组保存最大的距离
剪格子:回溯,剪枝
全球变暖:
简单的bfs(迷宫带路径输出,01迷宫)
队列操作,取节点,用节点,进节点
难一点的bfs(青蛙跳杯子)
每次比较队列里的不同的字符串,字符串保存在set集合中,每次bfs和当前两串‘*’之间的距离,
2.字符串
StringBuilder StringBuffer
回文:String.compareto (StringB(String str).reverse.toString) == 0;
桶排序:记录每个字符串中每个字母出现的次数
int book []=new int [26];
for(int i:n){book[str.charAt(i)-'A']++;}
sysout((char)('A'+i));
取所有子串:
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){ String str = s.subString(i,j+1);}}
是否单调递增:
abb型:
最长平衡子串:
Excel:
卡片:数组存放每一张卡片,循环字符串数组减去。
删除字符:留下的字典序最小,while(t>0){ 每次比较两个字符即可; t--;}
3.数论
欧拉筛 -- 求解范围内的质数以及判断某个数是否是质数:
private static boolean isprime(int n){
if(n<2){return false;}
boolean [] isprime = new boolean[n+1];
Arrays.fill(isprime,true);
//通过标记每个质数的倍数来筛选出所有的合数,如果一个数没有
for(int i=2;i * i <= n;i++){
if(isprime[i]){
for(int j= i * i;j<=n;j+=i){
isprime[j] = false;
}
}
}
return isprime[n];
}
因子/质因子分解--求解质因子个数:
private static int zyfj(int n) {
if(n<2) {
return 0;
}
int count=0;
for(int i=2;i*i<=n;i++){
while(n % i==0) {
count++;
n/=i;
}
}
if(n>1) {
count++;
}
return count;
}
唯一分解定理--求解约数个数:
private static int wyfj(int n) {
int count =1;
for(int i=2;i*i<=n;i++) {
int ans =0;
while(n % i ==0) {
ans++;
n/=i;
}
if(ans>0) {
count *= (ans+1);
}
}
if(n>1) {
count *=2;
}
return count;
}
仓库:所有的因子添加到集合中,遍历找答案
纯质数:数位拆分判断每一位是否为质数,boolean数组保存0-9[]的数是否为质数
大数:BigInteger,含有mod,mutiply,divide,pow, abs,
利用大数的gcd求(1-n的)lcm:
等差数列:d = (an - a1) / (n-1); Sn = n * (an+a1) / 2;
等比数列:q = an / a1 ^ (1/(n-1)); Sn = a1 * (1-q^n) / (1-q);
斐波那契数列:每60项数字的余数形成一个周期;
分数的表示:printf("%d / %d",a,b);
小数的表示:printf("%.2f",(double) a);
阶乘约数:桶排序存放质数次数;
等差素数数列:模拟数字和公差 ,while(isp(a+j)){a = a+j; cnt++;}寻找10个连续素数的公差
约数个数:取sqrt,每次+2;
大数取余,%即可取后n位;
4.日期
判断日期的合法性以及模拟一个日期:
记得重置二月份的天数:day[2] = 28;
格式化日期:SimpleDateFormat sdf = new SDF("yyyy-MM-dd HH:mm:ss");
将long->Date : Date d = new Date(long start);
将Date->long : long start = sdf.parse("2023-04-08 00:00:00").getTime();
跑步锻炼:每天星期一跑步:new Date(long start).toString.contains("01 "); -- 1后面含空格
5.模拟枚举
枚举:
顺子日期:
刷题统计:每天打卡题数形成数组,模拟天数(注意i++的位置)和日期
换瓶盖:模拟瓶盖数和饮料总数
模拟:
天干地支:两个数组分别存放天干地支,分别模拟1960年前后的年份,前面天干地支--,后面天干地支++,注意达到数组界限
时,天干地支取数组上界或下界;
玩具:直接找规律模拟即可
纸张尺寸:A1,for(int i=48;i<c[1];i++){ } -- 太妙了,模拟的是Ax尺寸的尺寸的次数
翻硬币:两个数组,遍历,若元素不同则翻动两个硬币,三元符号表示: c[i] =='*'?'o':'*';
6.二分贪心
贪心:
答疑:题目要求的是在中间时刻开始时,(即前一次答疑结束到下一次答疑的开始),
数组含多个元素的快速排序:Arrays.sort(nums,(a,b) -> (a[0]+a[1]+a[2]) - (b[0]+b[1]+b[2]))
for(int i=0;i<n;i++){for(int j=0;j<3;j++){ sum+=nums[i][j]; if(j == 1) ans+=sum;
}}
谈判:
付账:判断一个人的钱乘以n是否恰好等于总数 money *(n-1)<s?需要付完 : 选择方差最小的金额付款;
二分:
int l=0,r = 10000;
while(l<=r){
int mid = (l+r)>>1;
if(check()){ ret = mid ; r = mid -1;
}else{ l = mid+1;
}
} ret即是答案
递增三元组:双指针,a和c数组分别模拟一个指针的移动,遍历b数组,直到找到满足条件的下标;数组a找最后一个,数组c找第一个
分巧克力:按题目要求是分成正方形,即二分的题目求出符合题意的check()即可,count += (ab[i][0] / mid) * (ab[i][1] / mid );
路标:两个路标之间的距离<mid,不需要设置,否则在当前路标设置一个距离为mid的路标,不断重复模拟合适的mid。
7.基础知识
拷贝:答案存在小数+1的情况;
ASCII码:'0':48 A'65' a'97'
进制转换:Integer.toHex / toOct / toBina (将十进制转化为16 / 8 / 2 进制)
一次向List添加多个数据
ArrayList<>list = new ; list.addAll(Arrays.asList(2,3,23,32,32,23,32));
读文件 String Path = "D:\\lq\\b.txt";
BuffR in = new br(new inps(new fileinpt(new file(Path))));
String line = ""; while(){(line = in.readline())!= null}
8.暴力
位运算:两家医院分15批口罩,求分得的口罩数的差值尽可能的小
//模拟1-2^15种所有的可能s
for(int i=0;i<(1<<15);i++) {
int sum1=0;int sum2=0;
//j表示枚举每次的口罩将给那一家医院,在15位二进制数的
//情况下,1给第一家,0给第二家
for(int j=0;j<15;j++) {
if( (i & (1<<j) ) !=0) {
sum1 +=nums[j];
}else {
sum2 +=nums[j];
}
}
//每一种情况下,两家医院口罩数量的差值,保留最小的na一个
ans = Math.min(ans, Math.abs(sum1 -sum2));
}
倍数问题:一个数组找三个数,是k的倍数,求三数之和
从尾部开始暴力,for(int i=n-1;i>=2;i--) {
for(int j=i-1;j>=1;j--) {
for(int q = j-1;q>=0;q--) {
//剪枝 if(sum<ans) break;
//后面都小于,不必再判断
if(a[i]+a[j]+a[j-1]<ans) {
break;}}
//后面都小于,不必再判断
if(a[i]+a[i-1]+a[i-2]<ans) {
break;
}//(60%)
灯塔:暴力枚举每个点,计算它到灯塔的距离是否小于半径,即可判断能否被照到
递增序列:暴力枚举每个点的中心散发的左下,右上,右下,同一行,同一列的直线是否递增
真-暴力: //直接暴力三重循环
int count = 0;
for (int i = 0; i < 30; i++) {
for (int j = 0; j < 50; j++) {
int num = a[i][j];
//每一行
for(int t = i+1;t<30;t++) {
if(num<a[t][j]) {
count++;
}
}
//每一列
for(int t=j+1;t<50;t++) {
if(num<a[i][t]) {
count++;
}
}
//左下斜线
for(int t = i+1,tt =j-1;t<30&&tt>=0;t++,tt--){
if(num<a[t][tt]) {
count++;
}
}
//右上斜线
for(int t = i-1,tt=j+1;t>=0&&tt<50;t--,tt++) {
if(num<a[t][tt]) {
count++;
}
}
//右下斜线
for(int t=i+1,tt=j+1;t<30&&tt<50;t++,tt++) {
if(num<a[t][tt]) {
count++;
}
}
}
}
2019分解: 分解为3个不同数的和,有顺序:
i取前1/3,j取i后面,k取j后面,能保证取到的数不重复
for(int i=1;i<s/3+1;i++) {
for(int j=i+1;j<s;j++) {
for(int k=j+1;k<s;k++) {
卡片:三种卡片有6个不同的组合,n人至少需要i个:两层循环解决;
4平方和:拉格朗日定理
可以取相同的数:20 = 0 0 2 4,后面的数一定是最大的,
for (int i1=0;i1*i1<=n;i1++)
for (int i2=i1;i2*i2<=n;i2++)
for (int i3=i2;i3*i3<=n;i3++)
for (int i4=i3;i4*i4<=n;i4++)
if (i1*i1+i2*i2+i3*i3+i4*i4==n) {
字母阵列:求中心散射的八个方向直线上形成"lanqiao"
直接枚举8个点的方向:
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if(zhi[i][j]=='L') {//向8个方向寻找搜索
if(j+6<n&&zhi[i][j+1]=='A'&&zhi[i][j+2]=='N'&&zhi[i][j+3]=='Q'&&zhi[i][j+4]=='I'&&zhi[i][j+5]=='A'&&zhi[i][j+6]=='O') {
num++;//向右寻找
}
if(i+6<n&&zhi[i+1][j]=='A'&&zhi[i+2][j]=='N'&&zhi[i+3][j]=='Q'&&zhi[i+4][j]=='I'&&zhi[i+5][j]=='A'&&zhi[i+6][j]=='O') {
num++;//向下寻找
}
if(j-6>=0&&zhi[i][j-1]=='A'&&zhi[i][j-2]=='N'&&zhi[i][j-3]=='Q'&&zhi[i][j-4]=='I'&&zhi[i][j-5]=='A'&&zhi[i][j-6]=='O') {
num++;//向左寻找
}
if(i-6>=0&&zhi[i-1][j]=='A'&&zhi[i-2][j]=='N'&&zhi[i-3][j]=='Q'&&zhi[i-4][j]=='I'&&zhi[i-5][j]=='A'&&zhi[i-6][j]=='O') {
num++;//向上寻找
}
if(j+6<n&&i+6<n&&zhi[i+1][j+1]=='A'&&zhi[i+2][j+2]=='N'&&zhi[i+3][j+3]=='Q'&&zhi[i+4][j+4]=='I'&&zhi[i+5][j+5]=='A'&&zhi[i+6][j+6]=='O') {
num++;//向右下寻找
}
if(j-6>=0&&i+6<n&&zhi[i+1][j-1]=='A'&&zhi[i+2][j-2]=='N'&&zhi[i+3][j-3]=='Q'&&zhi[i+4][j-4]=='I'&&zhi[i+5][j-5]=='A'&&zhi[i+6][j-6]=='O') {
num++;//向左下寻找
}
if(i-6>=0&&j-6>=0&&zhi[i-1][j-1]=='A'&&zhi[i-2][j-2]=='N'&&zhi[i-3][j-3]=='Q'&&zhi[i-4][j-4]=='I'&&zhi[i-5][j-5]=='A'&&zhi[i-6][j-6]=='O') {
num++;//向左上寻找
}
if(i-6>=0&&j+6<n&&zhi[i-1][j+1]=='A'&&zhi[i-2][j+2]=='N'&&zhi[i-3][j+3]=='Q'&&zhi[i-4][j+4]=='I'&&zhi[i-5][j+5]=='A'&&zhi[i-6][j+6]=='O') {
num++;//向右上寻找
}
最大子矩阵:
四层循环遍历矩阵,从左上角遍历到右下角,每次取不同的子块来遍历,子矩阵最大最小值<limit
for(int i=N;i>0;i--) {
for(int j=M;j>0;j--) { // i*j的矩阵(右下角的坐标)
for(int x=0;x<=N-i;x++) {
for(int y=0;y<=M-j;y++) { //左上角坐标
int max = find_max(i,j,x,y);
int min = find_min(i,j,x,y);
private static int find_max(int i, int j, int x, int y) {
// 寻找最大值
int res = Integer.MIN_VALUE;
for(int n=x;n<x+i;n++) {
for(int m=y;m<y+j;m++) {
res = Math.max(res, arr[n][m]);
}
}
return res;
}