printf()输出格式小tips
#include<stdio.h>
#include<string.h>
int main()
{
char c, s[20];
int a=1234;
float f=3.141592653589;
double x=0.12345678912345678;
strcpy(s, "Hello,World");
c='\x41';
printf("a=%d\n", a);//按照十进制整数格式输出,显示 a=1234
printf("a=%d%%\n", a);//输出%号 结果 a=1234%
printf("a=%6d\n", a);//输出6位十进制整数 左边补空格,显示 a= 1234
printf("a=%06d\n", a);//输出6位十进制整数 左边补0,显示 a=001234
printf("a=%2d\n", a);//a超过2位,按实际输出 a=1234
printf("a=%-6d\n", a);///输出6位十进制整数 右边补空格,显示 a=1234
printf("f=%f\n", f);//浮点数有效数字是7位,结果 f=3.141593
printf("f=%6.4f\n", f);//输出6列,小数点后4位,结果 f=3.1416
printf("x=%lf\n", x);//输出长浮点数 x=0.123457
printf("x=%18.16lf\n", x);//输出18列,小数点后16位,x=0.1234567891234567
printf("c=%c\n", c); //输出字符 c=A
printf("c=%x\n", c);//以十六进制输出字符的ASCII码 c=41
printf("s[]=%s\n", s);//输出数组字符串s[]=Hello,World
printf("s[]=%6.9s\n", s);//输出最多9个字符的字符串 s[]=Hello,Wor
return 0;
}
排序
冒泡排序
int a[];
for(int i=0;i<a.length-1;i++)
{ //一轮过后已经选出最大的一个并排好,所以要-i
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1])//从小到大排序
{
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
//最坏情况下,时间复杂度为O{n(n-1)/2}
*快排
基于分治
1.确定分界点
2.调整区间
3.递归
//快排 2.0
public static void quicksort(int[] arr, int left, int right) {
if (left > right) {
return;
}
int base = arr[(left + right) / 2];//确定分界点
int i = left;
int j = right;
while (i <= j) {
while (arr[j] > base) {
j--;
}
while (arr[i] < base) {
i++;
}
if (i <= j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
j--;
i++;
}
}
quicksort(arr, left, j);
quicksort(arr, i, right);
}
//快排进阶,在乱序数组中找到排好序后的第几个数,时间大大优化
public static void quicksort(int[] arr, int left, int right, int k) {
if (left == right) {
System.out.println(arr[left]);
return;
}
int base = arr[(left + right) / 2];
int i = left;
int j = right;
while (i <= j) {
while (arr[j] > base) {
j--;
}
while (arr[i] < base) {
i++;
}
if (i <= j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
if (k <= j) {
quicksort(arr, left, j, k);
} else if (i <= k) {
quicksort(arr, i, right, k);
} else {
quicksort(arr, j + 1, i - 1, k);
}
}
*归并排序
基于分治
1.确定分界点:mid=(left+right)/2
2.递归排序left,right
3.归并 --合二为一
private static void merge_sort(int arr[], int left, int right) {
if (left >= right) {
return;
}
int mid = (left + right) / 2;
merge_sort(arr, left, mid);
merge_sort(arr, mid + 1, right);
int k = 0, i = left, j = mid + 1;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
for (i = left, j = 0; i <= right; i++, j++) {
arr[i] = temp[j];
}
}
堆排序
import java.util.Arrays;
import java.util.Scanner;
public class 堆排序 {
static int n;
private static void heapSort(int[] arr) {
for (int end = n - 1; end > 0; end--) {
maxheap(arr, end);
int temp = arr[0];
arr[0] = arr[end];
arr[end] = temp;
}
}
private static void maxheap(int[] arr, int end) {
int lastfa = (0 + end) % 2 == 0 ? (0 + end) / 2 - 1 : (0 + end) / 2;
for (int fa = lastfa; fa >= 0; fa--) {
int left = fa * 2 + 1;
int right = fa * 2 + 2;
if (right <= end && arr[right] > arr[fa]) {
int temp = arr[right];
arr[right] = arr[fa];
arr[fa] = temp;
}
if (arr[left] > arr[fa]) {
int temp = arr[left];
arr[left] = arr[fa];
arr[fa] = temp;
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
int arr[] = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
}
二分
整数二分
1.找中间值 mid=(l+r)/2
//区间[l,r]被划分为[l,mid]和[mid+1,r]时使用:
int bsearch_1(int l,int r){
while(l<r){
int mid=(l+r)/2;
if(check(mid)){
r=mid;
}else{
l=mid+1;
}
}
return l;
}
//区间[l,r]被划分为[l,mid-1]和[mid,r]时使用:
int bsearch_2(int l,int r){
while(l<r){
int mid=(l+r+1)/2;
if(check(mid)){
l=mid;
}else{
r=mid-1;
}
}
return l;
}
浮点数二分
//浮点数没有加一减一的问题,所以相对整数二分简单一些
//当范围小于1e-6时认为是解,如要求保留几位小数,则4位—》1e-6,5位-》1e-7
例:求一个数的平方根
double x;
double l=0,r=x;
while(r-l>1e-6){
double mid=(l+r)/2;
if(mid*mid>=x){
r=mid;
}else{
l=mid;
}
}
java快读和快输模板
import java.io.*;
public class Main {
private static StreamTokenizer st; //构建快读模块
private static int nextInt()throws IOException{
st.nextToken();
return (int)st.nval;
}
public static void main(String[] args) throws IOException{
st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));//初始化 StreamTokenizer
int N = nextInt(), M = nextInt();//变量N和M使用快读构造方法,构建;
int tmp;
int val[] = new int[N+1];
for (int i=1;i<=M;i++) val[nextInt()]++;
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));//构建快输模块
for (int i=1;i<=N;i++) {
while(val[i]!=0) {pw.print(i+" ");val[i]--;}
}
pw.close();//关闭,如果还要用,则改为pw.f
}
}
判断数字是否为回文数
int s = i, num = 0;
while (s != 0) {
num = num * 10 + s % 10;
s /= 10;
}
快输,快读(BufferedReader)
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String s = in.read() // 读入一个字符 可读入空格回车 但不抛弃回车
String s1 = in.readLine(); // 读入一行 可读入空格可读入回车 但会将回车抛弃
string s2[] = in.readLine().Split(" "); // 使用Split通过空格分割读入的一行字符串,存在s2中
//输入整数
5
1 3 2 5 6
int N = Integer.valueOf(in.readLine());
int arr[] = new int[n];
String s = in.readLine();
String s2[] = s.split(" ");
for (int i = 0; i < N; i++) {
arr[i] = Integer.parseInt(s2[i]);
}
//输入:
5
c d a bb e
reader.readLine()//读入第一行的数字
String str = reader.readLine();//读入第二行的字母
String[] s = str.split(" ");//把第二行的空格切走
Arrays.sort(s);//对切完后的字符串排序
StringBuilder sb = new StringBuilder();//把最后结果放在这里面
for(String st : s){
sb.append(st);
sb.append(" ");
}
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
主要使用 BufferedWriter类中的 write() 类进行输出。 当数据量大的时候一定要使用这个类进行输出,谨记!
需要注意的是 write() 不能直接输出int类型, 因为write(int a) 会输出其对应的ASCii码的字符 ,比如输出 65 会显示 A 详见代码:
int a = 65;
char b = '2';
String c = "3";
out.write(a);
out.write("\n");
out.write(b);
out.write("\n");
out.write(c);
out.write("\n");
out.flush();
输出:
A
2
3
所以当需要输出一个int类型的变量时, 可以用Integer.toString(int a)方法 将其变为字符串形式输出。
或者使用 + 拼接一个字符串,这样 参数整体就是一个字符串了,比如加一个换行符。详见代码:
int a = 65;
out.write(a + "\n");
out.write(Integer.toString(a));
out.flush();
输出:
65
65
//这里要注意在使用out输出之后,如果要换行,不能用System.out.println(),只能用out.writer("\n");来换行
————————————————
版权声明:本文为CSDN博主「Androids_lost_Sheep」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/GD_ONE/article/details/103480407
汉诺塔游戏(递归)
目的:A->B
过程:A->C,C->B=>A->B;
import java.util.Scanner;
public class 汉诺塔游戏 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
printHanoitower(n, "A", "B", "C");
}
static void printHanoitower(int n, String from, String to, String help) {
if (n == 1) {
System.out.println("move" + n + "from" + from + "to" + to);
} else {
printHanoitower(n - 1, from, help, to);
System.out.println("move" + n + "from" + from + "to" + to);
printHanoitower(n - 1, help, to, from);
}
}
}
重写compareto()自定义比较基准来进行排序
class job implements Comparable<job> {//构建工作对象
int s;
int t;
public job(int s, int t) {
this.s = s;
this.t = t;
}
public int compareTo(job other) {//由于要以工作对象的结束时间作为比较排序的基准,这里需要对comparable
//里的comparaTo函数进行重载
//int compareTo(T t)方法说明
//定义:比较此对象与指定对象的顺序。
//返回:负整数、零或正整数。如果该对象小于、等于或大于指定对象,则
//分别返回负整数、零或正整数。
//假如result返回1。Collections.sort(List)方法就是升序;
//假如result返回-1。Collections.sort(List)方法就是降序;
int x = this.t - other.t;
if (x == 0) {
return this.s - other.s;
} else {
return x;
}
}
}
java高精度模板题
Input
T输入包括多组 R 和 n。 R 的值占第 1 到第 6 列,n 的值占第 8 和第 9 列。
Output
对于每组输入,要求输出一行,该行包含精确的 R 的 n 次方。输出需要去掉前导的 0 后不要的 0 。如果输出是整数,不要输出小数点。
Sample Input
95.123 12
0.4321 20
5.1234 15
6.7592 9
98.999 10
1.0100 12
Sample Output
548815620517731830194541.899025343415715973535967221869852721
.00000005148554641076956121994511276767154838481760200726351203835429763013462401
43992025569.928573701266488041146654993318703707511666295476720493953024
29448126.764121021618164430206909037173276672
90429072743629540498.107596019456651774561044010001
1.126825030131969720661201
import java.math.BigDecimal;
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner sc=new Scanner(System.in);
while(sc.hasNext()) { //判断有无下一个输入数据
BigDecimal x=sc.nextBigDecimal();
int n=sc.nextInt();
BigDecimal ans=BigDecimal.ONE;
for(int i=0;i<n;i++) {
ans=ans.multiply(x);
//BigDecimal的乘法需要调用multiply()方法,乘以一个BigDecimal对象,返回一个BigDecimal对象
}
String s=ans.toPlainString();
//在这里要使用toPlainString()方法,默认的toString()方法在某些情况是科学计数法,错了很多次才知道
/*
* 例如样例:
* 0.000001 5
*/
int len=s.length();
int leadzero=-1;
boolean metdot=false;
for(int i=0;i<len;i++) {
if(leadzero==-1&&s.charAt(i)!='0') {
leadzero=i;
//把整数部分的0去掉
}
if(s.charAt(i)=='.') {
metdot=true;
//遇到了小数点,说明是小数
break;
}
}
if(metdot==true) {
s=s.substring(leadzero);
//遇到了小数点,说明是小数
len=s.length();
//重新计算s的长度,因为前面可能截断了整数部分的0
int releadzero=-1;
for(int i=len-1;i>=0;i--) {
if(s.charAt(i)!='0') {
releadzero=i+1;
//遇到第一个非零位置,其后的无效0截断
if(s.charAt(i)=='.') {
releadzero=i;
//遇到第一个非零位置是小数点,连小数点也截断
}
break;
}
}
s=s.substring(0,releadzero);
}
else {
//没有遇到小数点,是整数,不可能有无效0
;
}
System.out.println(s);
}
sc.close();
}
}
重写Arrays.sort()实现从大到小排序
package com.itheimajavase;
import java.util.Arrays;
import java.util.Comparator;
public class Day01 {
public static void main(String[] args) {
Integer[] arr = {4, 6, 3, 9, 1, 5, 8};
Mycomparator c = new Mycomparator(); // 实例化一个Comparator对象
Arrays.sort(arr, c);
for(Integer ele : arr) {
System.out.print(ele +" ");
}
}
// 运行后是从大到小排好序的
}
class Mycomparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
if(o1 > o2) // 默认是o1 < o2时返回-1, 一下同理
return -1;
if(o1 < o2)
return 1;
return 0;
}
}
进制问题
1<<16==2的16次方
1e6+10=1000010
方块数学小tip
一块长n,宽m的巧克力,能分成边长为x的正方形巧克力s块?s块为多少
公式:s=(n/x)*(m/x)
前缀合tips
一维数组:
//求l到r的和
s[i]=s[i-1]+arr[i]; //初始化前缀和数组
res=s[r]-s[l-1];
//二维前缀和
//利用前缀和
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+arr[i][j];//初始化
左上点坐标 x1,y1 右上点坐标 x2,y2
//求子矩阵的和
sum=s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y]
//三维前缀和
数论
质数判定
质数判定(试除法)
check(i){ //判断是否为质数,时间复杂度O(sqrt(n))
for(int i=2;i<=n/i;i++){
if(n%i==0){
return false;
}
}
return true
}
分解质因数(试除法)
//时间复杂度O(sqrt(n))
import java.util.Scanner;
public class 质因数分解 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
gcd(n);
}
static void gcd(int n) {
for (int i = 2; i <= n / i; i++) {
if (n % i == 0) {
int s = 0;
while (n % i == 0) {
n /= i;
s++;
}
System.out.println(i + " " + s);
}
}
if (n > 1) {
System.out.println(n + " " + 1);
}
}
}
质数筛
//埃式筛法,时间复杂度 O(nloglogn)
import java.util.Scanner;
public class 筛质数 {
static int N = 1000010;
static int primes[] = new int[N];
static boolean st[] = new boolean[N];
static int cnt = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
get_primes(n);
for (int i = 0; i < cnt; i++) {
System.out.println(primes[i]);
}
sc.close();
}
static void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes[cnt++] = i;
for (int j = 2 * i; j <= n; j += i) {
st[j] = true;
}
}
}
}
}
//线性筛法
时间复杂度 O(n)
import java.io.BufferedReader;
import java.io.BufferedWriter;
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 线性筛质数 {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
static ArrayList<Integer> primes = new ArrayList<>();
static boolean st[];
static int cnt = 0;
public static void main(String[] args) throws IOException {
int n = nextInt();
int m = nextInt();
st = new boolean[n + 1];
get_primes(n);
while (m-- > 0) {
int e = nextInt();
out.write(primes.get(e - 1) + "\n");
}
out.flush();
}
static void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes.add(i);
}
for (int j = 0; j < primes.size(); j++) {
if (primes.get(j) * i > n) {
break;
}
st[primes.get(j) * i] = true;
if (i % primes.get(j) == 0) {
break;
}
}
}
}
}
求约数
// 1、试除法求一个数所有的约数
求最大公约数
欧几里得算法(辗转相除法)
public static int gcd(int m,int n){
return n==0?m:gcd(n,m%n)
}
裴蜀定理
扩展欧几里得算法
void exgcd(int a,int b,long x,long y){
if(b==0){
x.v=1;
y.v=0;
return a;
}
long d= exgcd(b,a%b,y,x);
y.v-=(a/b)*(x.v);
return d
}
class Long{
long v;
public Long(long v){
this.v=v;
}
}
赛瓦维斯特定理
a , b > 1 , a b 的 最 大 公 约 数 = 1 ( 互 素 ) , 使 得 a x + b y = c , 无 正 整 数 解 的 c 最 大 为 , c = a b − a − b a,b>1,ab的最大公约数=1(互素),使得 ax+by=c,无正整数解的c最大为,c=ab-a-b a,b>1,ab的最大公约数=1(互素),使得ax+by=c,无正整数解的c最大为,c=ab−a−b
算术基本定理
所有正整数是一定可以唯一的分成为若干个质因子相乘
小tips
1.已知两个互质的数a和b,则这两个数最大不能组成的数为a*b-a-b;
2.求数的上取整:a/b=(a+b-1)/b(a/b上取整)
3.s-v除以n的结果x如果要求为n的倍数,则改式可以转换为,s%n的余数等于v%n的余数
4.(同余式)(a+b)%n=j等价于(a+b)=j(%n);同时一边的数可以加到另一边,符号改变即可–>a=j-b(%n);
判断闰年
5.1 年份能被4整除,但不能被100整除;
5.2 年份能被400整除;
year%100!=0&&year%4==0||year%400==0;
6.防止出现负余数: (a%b+b)%b
6.等差数列前n项和:前n项和公式为:Sn=n*a1+n(n-1)d/2或Sn=n(a1+an)/2
均值不等式
扩展欧几里得算法
此算法求 已知a和b,ax+by=(a和b的最大公约数)的x和y
import java.util.Scanner;
public class test {
static long x;
static long y;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try {
linearEquation(2, 7, 1);
System.out.println(x + " " + y);
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("无解");
}
}
public static long ext_gcd(long a, long b) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
long res = ext_gcd(b, a % b);
long x1 = x;
x = y;
y = x1 - a / b * y;
return res;
}
public static long linearEquation(long a, long b, long m) throws Exception {
long d = ext_gcd(a, b);
if (m % d != 0)
throw new Exception("无解");
long n = m / d;
x *= n;
y *= n;
return d;
}
}
DP问题
闫氏DP分析法
从集合角度分析DP问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9rsF0z3-1653210209939)(D:\桌面\笔记学习\images\闫氏dp.png)]
(01背包问题为例)
树状数组
时间复杂度:Olog(n)
用法:
1.单点修改
2.区间查询
树状数组下标必须从1开始
//树状数组的三个基本操作
int a[]; //原数组
int tr[]; //树状数组
int lowbit(int x){
return x&-x;
}
void add(int x,int v){ //单点修改
for(int i=x;i<=n;i+=lowbit(i)){
t[i]+=v;
}
}
void query(int x){ //区间查询前缀和
int res=0;
for(int i=x;i;i-=lowbit(i)){
res+=tr[i];
}
}
差分
差分是前缀和的逆运算
给定a[1],a[2],a[3],a[n]
构造差分数组b[N],使得a[i]=b[1]+b[2]+…b[i];
核心操作:将,a[l~r]全部加上c,等价于b[l]+=c,b[r+1]-=c
//一维差分
public class 拆分 {
static int N = 100010;
static int a[] = new int[N];
static int b[] = new int[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
for (int i = 1; i <= n; i++) {
a[i] = sc.nextInt();
add(i, i, a[i]);
}
for (int i = 1; i <= m; i++) {
int l = sc.nextInt();
int r = sc.nextInt();
int e = sc.nextInt();
add(l, r, e);
}
for (int i = 1; i <= n; i++) {
a[i] = a[i - 1] + b[i];
}
for (int i = 1; i <= n; i++) {
System.out.print(a[i] + " ");
}
}
static void add(int l, int r, int e) {
b[l] += e;
b[r + 1] -= e;
}
}
//二维差分
public class 拆分矩阵 {
static int N = 1010;
static int a[][] = new int[N][N];
static int b[][] = new int[N][N];
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException, InterruptedException {
String s = in.readLine();
String s1[] = s.split(" ");
int n = Integer.valueOf(s1[0]);
int m = Integer.valueOf(s1[1]);
int q = Integer.valueOf(s1[2]);
for (int i = 1; i <= n; i++) {
String s2 = in.readLine();
String s22[] = s2.split(" ");
for (int j = 1; j <= m; j++) {
a[i][j] = Integer.valueOf(s22[j - 1]);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
insert(i, j, i, j, a[i][j]);
}
}
while (q-- > 0) {
String s3 = in.readLine();
String s33[] = s3.split(" ");
int x1 = Integer.valueOf(s33[0]);
int y1 = Integer.valueOf(s33[1]);
int x2 = Integer.valueOf(s33[2]);
int y2 = Integer.valueOf(s33[3]);
int e = Integer.valueOf(s33[4]);
insert(x1, y1, x2, y2, e);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
out.write(a[i][j] + " ");
}
out.write("\n");
}
out.flush();
}
static void insert(int x1, int y1, int x2, int y2, int e) {
b[x1][y1] += e;
b[x1][y2 + 1] -= e;
b[x2 + 1][y1] -= e;
b[x2 + 1][y2 + 1] += e;
}
}
//三维差分 题目三体攻击(蓝桥杯真题)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class 三体攻击三维差分 {
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static int N = 1500000;
static int A, B, C, m;
static long s[] = new long[N];
static long b[] = new long[N];
static long bp[] = new long[N];
static int d[][] = new int[][] { { 0, 0, 0, 1 }, { 0, 0, 1, -1 }, { 0, 1, 0, -1 }, { 0, 1, 1, 1 }, { 1, 0, 0, -1 },
{ 1, 0, 1, 1 }, { 1, 1, 0, 1 }, { 1, 1, 1, -1 } };
static int op[][] = new int[N / 2][7];
// 映射数组
static int get(int i, int j, int k) {
return (i * B + j) * C + k;
}
// 判断当前状态有无毁坏的战舰,有则true,无则反之
static boolean check(int mid) {
b = Arrays.copyOf(bp, bp.length);
for (int i = 1; i <= mid; i++) {
int x1 = op[i][0], x2 = op[i][1], y1 = op[i][2], y2 = op[i][3], z1 = op[i][4], z2 = op[i][5], h = op[i][6];
b[get(x1, y1, z1)] -= h;
b[get(x1, y1, z2 + 1)] += h;
b[get(x1, y2 + 1, z1)] += h;
b[get(x1, y2 + 1, z2 + 1)] -= h;
b[get(x2 + 1, y1, z1)] += h;
b[get(x2 + 1, y1, z2 + 1)] -= h;
b[get(x2 + 1, y2 + 1, z1)] -= h;
b[get(x2 + 1, y2 + 1, z2 + 1)] += h;
}
Arrays.fill(s, 0);
for (int i = 1; i <= A; i++)
for (int j = 1; j <= B; j++)
for (int k = 1; k <= C; k++) {
s[get(i, j, k)] = b[get(i, j, k)];
for (int u = 1; u < 8; u++) {
int x = i - d[u][0], y = j - d[u][1], z = k - d[u][2], t = d[u][3];
s[get(i, j, k)] -= s[get(x, y, z)] * t;
}
if (s[get(i, j, k)] < 0)
return true;
}
return false;
}
public static void main(String[] args) throws IOException {
String s1 = in.readLine();
String s11[] = s1.split(" ");
A = Integer.valueOf(s11[0]);
B = Integer.valueOf(s11[1]);
C = Integer.valueOf(s11[2]);
m = Integer.valueOf(s11[3]);
String s2 = in.readLine();
String s22[] = s2.split(" ");
int pos = 0;
// 初始化原数组(前缀和数组)
for (int i = 1; i <= A; i++) {
for (int j = 1; j <= B; j++) {
for (int k = 1; k <= C; k++) {
s[get(i, j, k)] = Integer.valueOf(s22[pos++]);
}
}
}
// 初始化差分数组
for (int i = 1; i <= A; i++) {
for (int j = 1; j <= B; j++) {
for (int k = 1; k <= C; k++) {
for (int u = 0; u < 8; u++) {
int x = i - d[u][0];
int y = j - d[u][1];
int z = k - d[u][2];
int t = d[u][3];
bp[get(i, j, k)] += s[get(x, y, z)] * t;
}
}
}
}
// 进行操作
for (int i = 1; i <= m; i++) {
String s3 = in.readLine();
String s33[] = s3.split(" ");
for (int j = 0; j < 7; j++) {
op[i][j] = Integer.valueOf(s33[j]);
}
}
// 进行二分
int l = 1, r = m;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
System.out.println(r);
}
}
映射数组方法
二维数组A×B,映射为一维:下标如果是i,j,则 i×B+j
三维数组A×B×C,映射为一维:下标如果是i,j,k,则(i×B+j)×C+K
Flood Fill
针对网格图
图论问题
一、找 树的直径(一点到另一点的最长路径)
- 任取一点x,找到离它最远的点y
- 找到离y点最远的点z,点z到y的距离就是这个树的直径
贪心
特点:跳跃性很强,结论证明很难
解决方法:找相似,猜
DFS|BFS
dfs
bfs
// 将bfs看成一个队列,每次取队头元素,找与其相关的元素,添至队尾
// bfs适用与求带“最短”一类的问题
int distan[];// 判重数组兼移动距离数组
private static int bfs(position start, position end) {
// TODO Auto-generated method stub
Queue<position> queue = new LinkedList<>(); // 定义队列
for (int i = 0; i < r; i++) {
Arrays.fill(dis[i], -1); // 判重数组初始化
}
dis[start.x][start.y] = 0; // 表示起点位置,初始化距离为0
queue.offer(start); // 将起点放入队列
int dx[] = { -1, 0, 1, 0 }, dy[] = { 0, 1, 0, -1 }; // 表示偏移量,方向
while (!queue.isEmpty()) { // 如果当前队列里面不为空,则进行队列操作
position t = queue.poll(); // 取出队头元素并移除
for (int i = 0; i < 4; i++) { // 进行移动操作,上下左右
int x = t.x + dx[i];
int y = t.y + dy[i];
if (x < 0 || x >= r || y < 0 || y >= c)
continue; // 地图越界
if (gap[x][y] == '#')
continue; // 遇到障碍
if (dis[x][y] != -1)
continue; // 重复经过
dis[x][y] = dis[t.x][t.y] + 1; // 如果能过到这个位置上来,则这个点走的路程是上个位置走的路程+1
if (end.x == x && end.y == y)
return dis[x][y]; // 到终点了
queue.offer(new position(x, y)); // 将新状态放入队尾
}
}
return -1;
}
}
//定义位置对象
class position {
int x, y;
public position(int x, int y) {
// TODO Auto-generated constructor stub
this.x = x;
this.y = y;
}
}
数据结构
并查集
操作1:将两个元素合并
操作2:询问两个元素是否在一个集合当中
时间复杂度:近乎O(1)
基本原理:每个集合用一颗树来表示,树根的编号就是整个集合的编号,每个节点存储它的父节点,p[x]表示x的父节点
1.判断树根:if(p[x]==x)
2.求x的集合编号:while(p[x]!=x) x=p[x];
3.合并两个集合:px是x的集合编号,py是y的集合编号–>p[x]=y
模板题:
//并查集模板
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class 并查集 {
static int N = 10010;
static int p[] = new int[N];
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
static int find(int x) { //返回x的祖宗节点,路径压缩,关键
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
public static void main(String[] args) throws IOException {
String s1[] = in.readLine().split(" ");
int n = Integer.valueOf(s1[0]);
int m = Integer.valueOf(s1[1]);
for (int i = 1; i <= n; i++) { //树的节点初始化,必要步骤
p[i] = i;
}
while (m-- > 0) {
String s2[] = in.readLine().split(" ");
int op = Integer.valueOf(s2[0]);
int a = Integer.valueOf(s2[1]);
int b = Integer.valueOf(s2[2]);
if (op == 1) {
p[find(a)] = find(b); //合并操作,将a的树根接到b的树根上去
} else {
if (find(a) == find(b)) {
out.write("Y");
out.write("\n");
} else {
out.write("N");
out.write("\n");
}
}
}
out.flush();
}
}
实现单链表
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int N = (int) 1e5 + 10;
static int e[] = new int[N]; //节点的值
static int ne[] = new int[N]; //节点的next
static int head; // 头结点
static int index; //当前加入的值的下标
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
// 链表初始化
static void init() {
head = -1;
index = 0;
}
// 在头结点插入
static void addHead(int value) {
e[index] = value;
ne[index] = head;
head = index;
index++;
}
// 在某个结点后面插入
static void insert(int a, int value) {
e[index] = value;
ne[index] = ne[a];
ne[a] = index;
index++;
}
// 删除某个结点后面的数
static void delete(int k) {
ne[k] = ne[ne[k]];
}
public static void main(String[] args) throws IOException {
int M = Integer.valueOf(in.readLine());
init();
while (M-- > 0) {
String s[] = in.readLine().split(" ");
if (s[0].equals("H")) {
int value = Integer.valueOf(s[1]);
addHead(value);
} else if (s[0].equals("I")) {
int a = Integer.valueOf(s[1]);
int value = Integer.valueOf(s[2]);
insert(a - 1, value);
} else if (s[0].equals("D")) {
int k = Integer.valueOf(s[1]);
if (k == 0) {
head = ne[head];
} else {
delete(k - 1);
}
}
}
for (int i = head; i != -1; i = ne[i]) {
System.out.print(e[i] + " ");
}
}
}
树的存储
数是一种特殊的图,连通,无环,所以弄懂图的相关操作之后就可以
// 用邻接表存储
图的存储
// 用邻接表存储
//有向图
int N;// 有几个点
int h[N] // 头结点
int e[N] //当前节点的权值
int ne[N] //节点的next指针
int index=0;
void add(int a,int b){
e[index]=b;
ne[index]=h[a];
h[a]=index;
index++;
}
Arrays.fill(h,-1) //初始化每一个单链表的头结点为-1
//无向图
无向图跟有向图步骤一样,只是在add的步骤上,再多加一步,add(a,b),add(b,a);
图的遍历
// 深度优先遍历(深度优先搜索)
boolean st[];// 遍历时不能重复,所以要有一个判重数组
int dfs(int u){
st[u]=true; //st[u] 表示点u已经被遍历过了
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(!st[j]){
dfs(j);
}
}
}
// 宽度优先遍历
Queue <integer> queue=new ArraysList<>();
st[1]=true; //表示1号点已经被遍历过
queue.offer(1);
while(!queue.isEempty()){
int t=queue.poll();
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(!st[j]){
st[j]=true;
queue.offe
}
}
}