gcd
private static long gcd(long a,long b){
return (a==0?b:gcd(b%a,a));
}
并查集
class UnionFind {
private int[] parent;
private int[] size;
private int count;
public UnionFind(int n) {
this.parent = new int[n];
this.size = new int[n];
this.count = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
}
public int find(int p) {
while (p != parent[p]) {
parent[p] = parent[parent[p]];
p = parent[p];
}
return p;
}
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) {
return;
}
if (size[rootP] > size[rootQ]) {
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
} else {
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
}
count--;
}
public int getCount() {
return count;
}
}
线段树
import java.util.*;
class Node{
int l,r; //区间边界
int sum,lazyTag; //区间和,lazy标记
public Node(int l,int r){
this.l=l;
this.r=r;
}
}
public class segmentTree{
static Node[] tree = new Node[20];
static int[] arr = {1,3,5,7,9};
public static void main(String[] args) {
segmentTree.create(0,0,4);
segmentTree.update(0,1,3,1);
System.out.println(segmentTree.query(0,0,3));
}
public static void create(int node, int l, int r) {
tree[node] = new Node(l,r);
if (l == r) { //到叶子节点
tree[node].sum = arr[l];
return;
}
else {
int mid = (l + r) >> 1;
int left_node = (node << 1) + 1;
int right_node = (node << 1) + 2;
create(left_node, l, mid);
create(right_node, mid + 1, r);
tree[node].sum = tree[left_node].sum + tree[right_node].sum;
}
}
public static void update(int node,int l, int r,int val) {
if(tree[node].l > r || tree[node].r < l) { //不在需要修改的区间里
return;
}else if (tree[node].l >= l && tree[node].r <= r) { //完全包含于要求修改的区间
tree[node].sum += (tree[node].r-tree[node].l+1)*val;
tree[node].lazyTag+=val;
return;
} else { //不完全包含,需要向下查
if(tree[node].lazyTag!=0)
pushDowm(node); //懒标记下放
int left_node = (node<<1)+1;
int right_node = (node<<1)+2;
update(left_node,l,r,val);
update(right_node,l,r,val);
tree[node].sum = tree[left_node].sum + tree[right_node].sum; //更新完将数据传回给父节点
}
}
public static void pushDowm(int node) {
int left_node = (node<<1)+1;
int right_node = (node<<1)+2;
int val =tree[node].lazyTag;
tree[left_node].sum += (tree[left_node].r - tree[left_node].l + 1) * val;
tree[right_node].sum += (tree[right_node].r - tree[right_node].l + 1) * val;
tree[left_node].lazyTag += val;
tree[right_node].lazyTag += val;
tree[node].lazyTag = 0;
}
public static int query(int node,int l,int r) {
if (tree[node].l > r || tree[node].r < l) {
return 0;
}
else if (tree[node].l >= l && tree[node].r <= r) {
return tree[node].sum;
}
else {
if(tree[node].lazyTag != 0)
pushDowm(node);
int mid = (l + r) / 2;
int left_node = (node << 1) + 1;
int right_node = (node << 1) + 2;
return query(left_node, l, r) + query(right_node, l, r);
}
}
}
Dijkstra
package text2;
import java.util.*;
import java.io.*;
public class Dijkstra {
static int n,m;
static int g[][] = new int[10005][10005];//存放图
// static int dis[] = new int[n];//起点到每个点的最短距离
static int vis[] = new int[10005];//是否被标记过
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();//顶点数
m = scanner.nextInt();//边数
int s = scanner.nextInt();//图的起点
// Arrays.fill(dis, 0x3f3f3f3f);
for (int i = 0; i < n; i++) {
Arrays.fill(g[i], 0x3f3f3f3f);
g[i][i]=0;
}
Arrays.fill(vis, 0);
for(int i=0;i<m;i++) {
int v1=scanner.nextInt();
int v2=scanner.nextInt();
int weight=scanner.nextInt();
g[v1][v2]=weight;
g[v2][v1]= weight;
}
dijkstra(0);
System.out.print(g[0][2]);
}
//固定模板
public static void dijkstra(int s) {
for(int i=0;i<n;i++) {
int t=-1;
int min = 0x3f3f3f3f;
//找距离起点最近的一个点t(而且未被访问过)
for(int j=0;j<n;j++) {
if(vis[j]==0&&(t==-1||g[s][j]<min)) {
min = g[s][j];
t = j;
}
}
vis[t] = 1;
//以u为中间点,修正从【起点s】到未访问各点的距离
for(int j=0;j<n;j++) {
if(vis[j]==0) {
if(g[s][t]+g[t][j]<g[s][j]) {
g[s][j] = g[s][t]+g[t][j];
//此处还可以加路径
}
}
}
}
}
}
Floyd
import java.util.Scanner;
public class Main{
static int m,n,u,v,w;
static final int N=150;
static final int INF=0x3f3f3f3f;
static long[][] g=new long[N][N];
static void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(g[i][j]>g[i][k]+g[k][j]){
g[i][j]=g[i][k]+g[k][j];
}
}
}
}
}
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
n=cin.nextInt();
m=cin.nextInt();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
g[i][j]=i==j?0:INF;
}
}
while(m-->0){
u=cin.nextInt();
v=cin.nextInt();
w=cin.nextInt();
if(w<g[u][v]){
g[u][v]=g[v][u]=w;
}
}
floyd();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(j!=1){
System.out.print(" ");
}
System.out.print(g[i][j]);
}
System.out.println();
}
}
}
计算CnmC^m_nCnm当n和m足够大的时候,无法用long的范围计算,就需要取模运算,由于取模无法进行除法操作,所以可以使用扩展欧几里得计算。
扩展欧几里得
import java.util.HashMap;
import java.util.Map;
public class LargeCombinationMod {
private static final int MOD = 1000000007; // 取模的素数
// 计算a的阶乘对MOD取模的结果
private static long factorialMod(long a) {
long result = 1;
for (long i = 2; i <= a; i++) {
result = (result * i) % MOD;
}
return result;
}
// 使用扩展欧几里得算法计算逆元
private static long modInverse(long a, long m) {
long m0 = m, t, q;
long x0 = 0, x1 = 1;
if (m == 1) return 0;
// 应用扩展欧几里得算法
while (a > 1) {
q = a / m;
t = m;
m = a % m, a = t;
t = x0;
x0 = x1 - q * x0;
x1 = t;
}
// 使结果为正
if (x1 < 0) x1 += m0;
return x1;
}
// 计算组合数C(n, m) mod MOD
public static long combinationMod(long n, long m) {
// 如果m大于n的一半,利用对称性减少计算量
if (m > n - m) {
m = n - m;
}
// 计算阶乘的模值
long nFactorial = factorialMod(n);
long mFactorial = factorialMod(m);
long nmFactorial = factorialMod(n - m);
// 计算逆元
long mInv = modInverse(mFactorial, MOD);
long nmInv = modInverse(nmFactorial, MOD);
// 计算组合数模值
long result = ((nFactorial * mInv) % MOD * nmInv) % MOD;
return result;
}
public static void main(String[] args) {
long n = 1000000; // 示例输入,可以根据需要调整
long m = 500000; // 示例输入,可以根据需要调整
System.out.println(combinationMod(n, m));
}
}
树状数组
class Solution {
int n = 20001;
int[] tr = new int[n+1];
int lowbit(int x){
return x & -x;
}
void add(int x, int c){
for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}
int query(int x){
int res = 0;
for(int i = x; i > 0; i -= lowbit(i)) res += tr[i];
return res;
}
public List<Integer> countSmaller(int[] nums) {
LinkedList<Integer> res = new LinkedList<>();
for(int i = nums.length-1; i >= 0; i--){
nums[i] += 10001;
res.addFirst(query(nums[i]-1));
add(nums[i],1);
}
return res;
}
}
分数取模运算
由费马小定理:
a^(p-1) mod p = 1 mod p
a * a^(p-2) mod p = 1 mod p
a^(p-2) mod p = a^(-1) mod p
(b/a) % p = b * a^(-1) % p = b * a^(p-2) % p
/**
* 分数求模
* 费马小定理(前提是模是素数)
* a^(p-1) mod p = 1 mod p
* a * a^(p-2) mod p = 1 mod p
* a^(p-2) mod p = a^(-1) mod p
* (b/a) % p = b * a^(-1) % p = b * a^(p-2) % p
*
* @param a 分母
* @param b 分子
* @return (b / a) % mod
*/
public static long fractionMod(long a, long b, long mod) {
// 这里使用上面的模快速幂的方法
return mul(b, quickPower(a, mod - 2, mod), mod);
}
/**
* 模快速幂
*
* @param x
* @param n
* @return x^n % mod
*/
public static long quickPower(long x, long n, long mod) {
if (n == 0) return 1;
if (n == 1) return x % mod;
long tmp = quickPower(x, n >> 1, mod);
// mul方法即为上面的模乘
return (n & 1) == 0 ? mul(tmp, tmp, mod) : mul(x, mul(tmp, tmp, mod), mod);
}
/**
* 模加
*
* @param x
* @param y
* @return (x + y) % mod
*/
public static long add(long x, long y, long mod) {
return ((x % mod) + (y % mod)) % mod;
}
/**
* 模乘
*
* @param x
* @param y
* @return x * y % mod
*/
public static long mul(long x, long y, long mod) {
return ((x % mod) * (y % mod)) % mod;
}
KMP
public class KMP {
public int indexOf(String source, String pattern) {
int i = 0, j = 0;
char[] src = source.toCharArray();
char[] ptn = pattern.toCharArray();
int sLen = src.length;
int pLen = ptn.length;
int[] next = getNext(ptn);
while (i < sLen && j < pLen) {
if (j == -1 || src[i] == ptn[j]) {
i++;j++;
} else {
j = next[j];
}
}
if (j == pLen)
return i - j;
return -1;
}
public int[] getNext(char[] p) {
int pLen = p.length;
int[] next = new int[pLen];
int k = -1;
int j = 0;
next[0] = -1; // next数组中next[0]为-1
while (j < pLen - 1) {
if (k == -1 || p[j] == p[k]) {
k++;j++;
next[j] = k;
} else {
k = next[k];
}
}
return next;
}
}
字典树(前缀树)
class Trie {
Trie[] chlidren;
boolean is_exist;
public Trie() {
chlidren = new Trie[26];
is_exist = false;
}
public void insert(String word) {
Trie tree = this;
for(int i=0;i<word.length();i++){
int now = word.charAt(i)-'a';
if(tree.chlidren[now]==null){
tree.chlidren[now] = new Trie();
}
tree = tree.chlidren[now];
}
tree.is_exist = true;
}
public boolean search(String word) {
Trie tree = this;
for(int i=0;i<word.length();i++){
int now = word.charAt(i)-'a';
if(tree.chlidren[now]==null)
return false;
tree = tree.chlidren[now];
}
return tree.is_exist;
}
public boolean startsWith(String word) {
Trie tree = this;
for(int i=0;i<word.length();i++){
int now = word.charAt(i)-'a';
if(tree.chlidren[now]==null)
return false;
tree = tree.chlidren[now];
}
return true;
}
}