ACM训练整理的一些内容,,不知道放哪 就丢这吧
欧拉函数模板
int r[] = new int [MAXN]; r[1] = 1; for(int i = 2; i < MAXN; i++) r[i] = i; for(int i = 2; i < MAXN; i++) if(r[i] == i) for(int j = i; j < MAXN; j += i) r[j] = r[j] / i * (i - 1);
快速幂模板 x^n
static long pow(long x,long n) { long res = 1; while(n>0) { if(n%2==1) res = res*x%MOD; x = x*x%MOD; n/=2; } return res; }
扩展欧几里得算法模板
public static int extendgcd(int a,int b){ if(b==0){ x=1; y=0; return a; } int d=extendgcd(b,a%b); int temp=x; x=y; y = temp-a/b*x; return d; }
求组合数的预处理模板 对1000000007取余
static void PreWork() { for (int i=0;i<=1000;i++) C[i][0]=1; for (int i=1;i<=1000;i++) for (int j=1;j<=1000;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%INF; }
中国剩余定理 普通版本模板 HDU 1573 参考:http://blog.csdn.net/a601025382s/article/details/10296577
for(int i = 0;i<m;i++) a[i] = in.nextInt(); // 除数,不一定互质 for(int i = 0;i<m;i++) b[i] = in.nextInt(); //余数 int m1 = a[0],r1 = b[0],m2,r2; int flag = 0; for(int i=1;i<m;i++) { m2=a[i]; r2=b[i]; int c=r2-r1; int d = extendgcd(m1,m2);//d=gcd(m1,m2);x*m1+y*m2=d; if(c%d!=0) { flag =1; break; } int t=m2/d; x=(c/d*x%t+t)%t; r1=m1*x+r1; m1=m1*m2/d; }
r1 为最小整数解 m1*i+r1 (i = 0,1,2.....) 都是满足条件的解
除法取模 (费马小定理)
求 a / b = x (mod M)
只要 M 是一个素数,而且 b 不是 M 的倍数,就可以用一个逆元整数 b’,通过 a / b = a * b' (mod M)
,来以乘换除。
费马小定理说,对于素数 M 任意不是 M 的倍数的 b,都有:
b ^ (M-1) = 1 (mod M)
于是可以拆成:
b * b ^ (M-2) = 1 (mod M)
于是:
a / b = a / b * (b * b ^ (M-2)) = a * (b ^ (M-2)) (mod M)
也就是说我们要求的逆元就是 b ^ (M-2) (mod M)
求解fibonacci数列 矩阵快速幂 对10000取模
import java.util.Scanner; public class Main { private static final int MOD = 10000; private static Node base; private static Node ans; public static void main(String[] args) { base = new Node(); ans = new Node(); base.m = new int [2][2]; ans.m = new int [2][2]; Scanner in = new Scanner (System.in); while(in.hasNext()) { int n = in.nextInt(); if(n==-1) break; System.out.println(fast_mod(n)); } } static int fast_mod(int n) // 求矩阵 base 的 n 次幂 { base.m[0][0] = base.m[0][1] = base.m[1][0] = 1; base.m[1][1] = 0; ans.m[0][0] = ans.m[1][1] = 1; // ans 初始化为单位矩阵 ans.m[0][1] = ans.m[1][0] = 0; while(n!=0) { if(n % 2 == 1) //实现 ans *= t; 其中要先把 ans赋值给 tmp,然后用 ans = tmp * t ans = multi(ans, base); base = multi(base, base); n >>= 1; } return ans.m[0][1]; } static Node multi(Node a, Node b)//定义矩阵乘法 { Node tmp = new Node(); tmp.m = new int [2][2]; for(int i = 0; i < 2; ++i) { for(int j = 0; j < 2; ++j) { tmp.m[i][j] = 0; for(int k = 0; k < 2; ++k) tmp.m[i][j] = (tmp.m[i][j] + a.m[i][k] * b.m[k][j]) % MOD; } } return tmp; } static class Node{ int m[][]; } }
斯特林数 (划分集合的方法数)
static void init() { s[1][1]=1; for(int i=2; i<=1000; i++) { for(int j=1; j<=i; j++) { s[i][j]=(s[i-1][j-1]+j*s[i-1][j])%INF; } } }
待补充。。。