Nobleman__ ACM 比賽模板 (C++ && Java)個人總結 (不斷更新) (自用)
阿新 • • 發佈:2019-01-20
- 宣告 : 本人剛學演算法一年,都是自己做題常用的模板,不時總結下。
大致分為:亂七八糟, 數論,圖論,動態規劃,幾何,Java
還有一些奇葩定理,
奇葩定理:
【1】高效求出n的約數的個數:
對 數 X 做質因數分解, 結果假定是 1^1 * a ^ A * b ^ B .... z ^ Z , 那 X 的因數個數應該是 (A+1) * (B+1) * .... (Z+1) - 1
而 X^2 的因數個數應該是 (2*A + 1) * (2*B + 1) * ... (2*Z + 1) -1 ....
比如 12 可以寫做事 1 * 2^2 * 3, 所以 12 的因數數量是 (2+1) * (1+1) - 1 = 5 個, 分別是 1 2 3 4 6
而 12^2 = 144 有 (2*2+1) * (2*1+1) - 1 = 14 個, 分別是 1 2 3 4 6 8 9 12 16 18 24 36 48 72
【2】快速判斷 : 如果 (n&m) == m 為奇數
亂七八糟模板
- 標頭檔案,巨集定義,讀入掛
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <bitset>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
#include <iomanip>
#define ll long long
#define ull unsigned long long
#define PI acos(-1.0)
#define eps 1e-12
#define fi first
#define se second
#define MEM(a,b) memset((a),(b),sizeof(a))
#define mod(x) ((x)%MOD)
#define pii pair<int,int>
#define wz cout<<"-----"<<endl;
const int INF_INT = 2147483647;
const ll INF_LL = 9223372036854775807LL;
const ull INF_ULL = 18446744073709551615Ull;
const ll P = 92540646808111039LL;
const ll maxn = 1e5 + 10, MOD = 1e9 + 7;
const int Move[4][2] = {-1,0,1,0,0,1,0,-1};
const int Move_[8][2] = {-1,-1,-1,0,-1,1,0,-1,0,1,1,-1,1,0,1,1};
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
- 結構體過載運算子
//與平時cmp函式 相反
bool operator < (const node &p) const {
return r > p.r;
}
資料結構
- 樹狀陣列
/*
單點更新,區間查詢,(也可區間更新加),逆序對等等
*/
int lowerbit(int x) {
return x & -x;
}
void add(int p, int x) {
while (p < maxn) {
d[p] += x;
p += lowerbit(p);
}
}
int sum(int p) {
int res = 0;
while (p) {
res += d[p];
p -= lowerbit(p);
}
return res;
}
數論模板
- 快速冪
ll quick_pow(ll a,ll b) {
ll res = 1;
while (b) {
if (b & 1) {
res = a * res;
}
a = a * a;
b >>= 1;
}
return res;
}
- 矩陣快速冪
#include<bits/stdc++.h>
#define ll long long
#define mod(x) ((x)%MOD)
using namespace std;
const ll MOD = 1e9 + 7;
struct mat{
ll m[3][3];
}a,ans,unit;
void init() {
memset(unit.m,0,sizeof(unit.m));
memset(a.m,0,sizeof(a.m));
unit.m[0][0] = 1;
unit.m[1][1] = 1;
a.m[0][0] = 3;
a.m[0][1] = 1;
a.m[1][0] = 1;
a.m[1][1] = 3;
}
mat operator * (mat m1,mat m2) {
mat t;
ll r;
for(int i = 0;i < 3;i++) {
for(int j = 0;j < 3;j++) {
r = 0;
for(int k = 0;k < 3;k++) {
r = mod(r*1ll + mod(mod(m1.m[i][k])*1ll*mod(m2.m[k][j])));
}
t.m[i][j] = r;
}
}
return t;
}
mat quick_pow(ll x) {
mat t = unit;
while(x) {
if(x & 1) {
t = t*a;
}
a = a*a;
x >>= 1;
}
return t;
}
int main(){
init();
ans = quick_pow(n);
}
- 素數的兩種篩法
bool isp[maxn];
int p[maxn], len;
bool isp[100];
void init() {
int m = (int)sqrt(maxn+0.5);
for(int i = 2;i <= m;i++) {
if(!isp[i]) {
for(int j = i*i;j <= maxn;j += i) {
isp[j] = true;
}
}
}
}
void init() { //推薦這個,較快
isp[0] = isp[1] = true;
for (int i = 2; i < maxn; i++) {
if(!isp[i]) p[++len] = i;
for (int j = 1; j <= len && p[j]*i < maxn; j++) {
isp[i*p[j]] = true;
if (i%p[j] == 0) break;
}
}
}
- 尤拉函式
在數論,對正整數n,尤拉函式是小於n的正整數中與n互質的數的數目(φ(1)=1)。
int euler_phi(int n){ //單個值
int m = (int)sqrt(n + 0.5);
int ans = n;
for (int i = 2;i <= m;i++){
if (n%i == 0){ //如果存在素因子
ans = ans/i*(i-1);
while (n%i == 0) n/=i;
}
}
if(n > 1) ans = ans/n*(n-1); //考慮n本身
return ans;
}
void phi_table(int n,int *phi){ //尤拉表
for (int i = 1;i <= n;i++) phi[i] = i;
for(int i = 2;i <= n;i++){
if(phi[i] == i){ //類似於Eratosthenes篩法這裡
for(int j = i;j <= n;j+=i){
phi[j] = phi[j]/i*(i-1);
}
}
}
}
- 歐幾里得GCD,擴充套件~
歐幾里德演算法又稱輾轉相除法,用於計算兩個整數a,b的最大公約數(greatest common divisor)。
擴充套件歐幾里德演算法是用來在已知a, b求解一組x,y,使它們滿足貝祖等式: ax+by = gcd(a, b) =d(解一定存在,根據數論中的相關定理)。擴充套件歐幾里德常用在求解模線性方程及方程組中。
ll gcd(ll a,ll b) {
return b == 0 ? a : gcd(b, a % b);
}
void egcd(ll a, ll b, ll &d, ll &x, ll &y) {
if(!b) d=a,x=1,y=0;
else egcd(b, a % b, d, y, x),y -= x * (a / b);
}
- 逆元
方程ax≡1(mod p),的解稱為a關於模p的逆,當gcd(a,p)==1(即a,p互質)時,方程有唯一解,否則無解。
對於一些題目會要求把結果MOD一個數,通常是一個較大的質數,對於加減乘法通過同餘定理可以直接拆開計算,但對於(a/b)%MOD這個式子,是不可以寫成(a%MOD/b%MOD)%MOD的,但是可以寫為(a*b^-1)%MOD,其中b^-1表示b的逆元。
ll getinv (ll a,ll p) {
ll d, x, y;
egcd (a, p, d, x, y);
return (x + p) % p == 0 ? p : (x + p) % p;
}
- 中國剩餘定理(CRT) ,擴充套件~
中國剩餘定理給出了以下的一元線性同餘方程組:
假設整數m1,m2, ... ,mn兩兩互質,則對任意的整數:a1,a2, ... ,an,方程組 有解,即x,擴充套件剩餘定理就是m1,m2···mn,這幾個數不兩兩互質的情況
// M 為 lcm(m1,m2...,mn)
ll CRT(ll M){
ll sum=0,tmp,v;
for (int i=1;i<=cnt;i++){
tmp=M/m[i];
v=getInv(tmp,m[i]);
sum=(sum+tmp*a[i]*v)%M;
}
return sum;
}
/*以下是ECRT*/
///這裡的是從下標是從1開始, r陣列代表 餘數,m 陣列代表除數
bool merge(ll &a1,ll &m1,ll a2,ll m2){
ll c,d,x,a3,m3;
c=a2-a1;d=__gcd(m1,m2);
if (c%d!=0) return false;
c=c/d;m1=m1/d;m2=m2/d;
x=getinv(m1,m2);
x=(x*c)%m2;
x=x*(m1*d)+a1;
m3=m1*m2*d;
a3=(x%m3+m3)%m3;
a1=a3;m1=m3;
return true;
}
ll ECRT(){
ll A=r[1],M=m[1];
for (int i=2;i<=n;i++) //無解返回 -1
if (!merge(A,M,r[i],m[i]))
return -1;
return (A%M+M)%M;
}
- 錯排公式
問題: 十本不同的書放在書架上。現重新擺放,使每本書都不在原來放的位置。有幾種擺法?
這個問題推廣一下,就是錯排問題,是組合數學中的問題之一。考慮一個有n個元素的排列,若一個排列中所有的元素都不在自己原來的位置上,那麼這樣的排列就稱為原排列的一個錯排。 n個元素的錯排數記為D(n)。 研究一個排列錯排個數的問題,叫做錯排問題或稱為更列問題。
//dp[i] = (i - 1)*(dp[i - 1] + dp[i - 2]); i > 2
ll a = 0,b = 1,c;
for (int i = 3; i <= n; i++) {
c = ((i - 1) * 1ll * (a + b)) % MOD;
a = b;
b = c;
}
printf("%lld\n",c);
- O(n) 求組合數
從開始從左到右遞推,注意爆int
C[0] = 1;
for(int i = 1; i <= n; i++)
C[i] = C[i - 1] * (n - i + 1) / i;
卡特蘭數列
h(n)=C(2n,n)/(n+1) (n=0,1,2,...)
h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,...)
C(m+n,n)−C(m+n,n−1)
階乘逆元
fac[0] = 1;
for (int i = 1; i <= maxn; i++)
fac[i] = mod(fac[i - 1] * i);
rfac[maxn] = qpow(fac[maxn],MOD - 2);
for (int i = maxn;i > 0; i--)
rfac[i - 1] = mod(rfac[i] * i);
- Lucas
求,其中p為質數
ll C(ll nn, ll mm) {
ll up = 1, down = 1;
for (int i = nn - mm + 1; i <= nn; i++) up = mod(up * 1ll *i);
for (int i = 1; i <= mm; i++) down = mod(down * 1ll *i);
return mod(up * qpow(down, MOD - 2));
}
ll lucas(ll n, ll m) {
if(m == 0) return 1;
return mod(lucas(n / MOD, m / MOD) * 1ll * C(n % MOD,m % MOD));
}
- 斯特林公式,計算階乘
公式如下:
化簡如下: