0.
一些很 sb 但是總是忘記的轉換(多為數論,update lasting):
1、模改加減乘除 : \(x\%y = x-\lfloor x/y \rfloor *y\)
2、組合數的幾個吸收恆等式:
3、看到個組合數考慮兩種處理方法:
第一個很簡單,康康能不能用二項式定理逆轉成一個指數
第二個也挺簡單(雖說一般來講就是要上個板子了),組合數拆開,然后轉化為 法法塔 的形式,然后卷起來
4、看到乘乘除除帶指數的題目莫要慌張:
CC 是個好地方,每做一道題就能學到點東西...
一些多個數乘乘除除,甚至帶指數,答案可能肥腸大的題,我們可以轉 ln 之后加起來,若有指數 k 我們令原數乘 k 后累加,最后 exp 回來保留精度輸出
例如 : ${x*y}\over t^k $ 我們可以變成 \(exp( ln(x)+ln(y)-ln(t)*k )\) ,算出來的結果帶有一定的精度誤差(但是應該不超過 1e-6 )
要注意的是, c++ 里面沒有 ln 函數, 但 log 的底數默認為自然數對數 e
其次,由於是計算機內部進行牛頓迭代完成 ln 和 exp ,所以運算速度還是夠快的(基本視為 O(1)?),但是如果精度要求實在變態(高精?【霧)那就只能手寫牛頓迭代了吧(口胡)
5、看到一些詭異的遞推處理莫要慌張:
可以先手玩一下樣例,然后康康是不是有一點神奇的地方呢(好吧這種事情大家都知道的,可能是因為我是菜雞才會碰到這種情況的時候手足無措),不過能否發現規律就不知道了...QwQ
1.
點分治 向下遞歸的時候兩種寫法(是否判斷當前子節點為上層點分樹中的父節點)都不會鍋:
2.
枚舉子集方法有三,暴力不說,枚舉子集網上挺多,但復雜度...爆炸,至於另一種玄學算法總感覺很像 FWT (其實就是 FWT 里面出來的...?):
for(rint i=1;i<=m;++i)x=read(),++cnt[x];
for (int len = 2; len <= (1 << n); len <<= 1) {
for (int i = 0; i <= lim; i += len)
for (int j = i, k = i + len / 2; k < i + len; j++, k++)
cnt[j] += cnt[k];
}
3.
判斷數列 \(\{a_n\}\) 中的每個數乘上一個非負系數后是否可以構成 T 時,我們可以把這些數中最小的 x 拿出來,讓剩下的數和 T 滿足: \(sum = T (mod x)\) ,也就是模 x 下同余,然后點 \(u\) 向模 x 意義下的 \(u+c_i\) 連一條邊,長度為減去的 x 個數,然后跑最短路,康康最短距離乘上 x 是否小於等於 \(\lfloor T / x\rfloor\) 就好了
4.
若三點在某一條經過原點的直線上的投影中心對稱,設三點坐標分別為 \((xa,ya),(xb,yb),(xc,yc)\),則 \((ya+yc-2 * yb,-xa-xc+2 * xb)\) 為該直線上一點,其中 B 點的投影為對稱中心
5.
對於一棵樹每次標記一條路徑,路徑上點對可相互到達,求多次標記后可相互到達的點對數,可以轉化為 dfs 序,然后樹剖完了線段樹上掃描線,二維數點求, ZJOI 考過,然而卡常(而且我這只菜雞也沒想出來)
6.
O(1) 求 1~n 的異或和:
inline int calc(Rg int n){int t=n&3;return t&1?(t/2^1):(t/2^n);}
上面只是害人的簡化寫法,真實應該是這樣寫的:
inline int calc(Rg int n){
int t=n&3;
if(!t) return n;
if(t==1) return 1;
if(t==2) return n+1;
if(t==3) return 0;
}
可以考慮用歸納法證明
7.
O(1) GCD:
zzq 大佬的 blog 里面有寫,我還搬下來做過板子...
某些 數據下會比帶 log 的算法高到不知道哪里去,然鵝隨機情況嘛...咳咳,我只能說,人家 O(1) 是要預處理的...
8.
O(1) 前綴 k 次和:
類似這么個式子: \(\sum_{i=0}^n i^k\) (雖說左邊界是 0 是 1 沒什么關系,畢竟 k 也不會等於 0 )
對於 k=1 : 原式= \((n+1)n\over 2\)
對於 k=2 : 原式= \(n(n+1)(2n+1)\over 6\) 或者 \(n(n+{1\over 2})(n+1)\over 3\) 也挺好記的
對於 k=3 : 原式= \((n+1)^2n^2\over 4\) ,其實就是 k=1 的情況平方了一下...
還有很多可以 O(1) 計算的東西,具體可以看這里
9.
對於集合 S 所有子集的異或和取值中,每種取值出現次數相等,即 S 的任意子集得到的異或和值為 x 的概率是相等的 ( x 為 S 所有子集異或和取值) 證明
10.
對於一棵 n 節點的帶編號樹,它的生成樹數量為 \(n^{n-2}\) 個(可用 Prufer 序列證明)
11.
斐波那契數列\(f(n)=(1,1,2...)\)的前綴和數列\(S(n)\)滿足:
歸納法證明:
當 n=1 時,原式成立
假設 \(S(n-1)=f(n+1)-1\) 成立,那么有:
\[S(n)=S(n-1)+f(n)=f(n+1)+f(n)-1=f(n+2)-1 \]
證畢
12.
在模 p ( p 為質數)意義下,有:
證明? 不會,背結論吧... (貌似要用唯一分解整環什么的,反正我不會...)
emmm...話說蒟蒻我好像想到了一個另類解法的開頭,就是我們對於左邊的式子展開,然后把除了最高項的每一項都提取出一個 \((p-1)!\) ,然后威爾遜定理搞一搞,發現這玩意兒模 p 意義下就是 p-1 ,(好像並沒有什么軟用,因為 p-1 並不等於 0 ),然后作者太懶不打算想,於是就咕掉了...(估計也是證不出來...)
不過還有另一種隨意的解法,就是我們發現左邊的式子必然是等於 0 的,然后右邊的式子也等於 0 ...
(就是說左邊的 x 加上 1~p-1 的所有數,總有一個是等於 0 的,而后面式子有 \(x^{p-1}-1\) ,當 x=1~p-1 時費馬小定理可得原式等於 0 ,當 x=0 時前面又有個 x ...),於是等式兩邊恆等於 0 ? 總之記住這個詭異的性質...
13.
恆等式:
proof:
14.
一些數論變化:
(1)
proof:
n=1:
原式成立
n>1:
(2)
proof:
太迷了不會...
假設 ij 有質因子 d , d在 i 中出現 a 次, j 中出現 b 次
考慮 gcd(i,j)=1 ,那么同一個 d 不可能被 p 和 q 同時整除,於是我們分三類情況討論取值范圍:
\(d\mid p , d\nmid q\) : 這樣我們發現 \({pj\over q}\) 取遍 $d^{b+1} $~ \(d^{b+a}\) 的倍數
\(d\nmid p , d\mid q\) : 這樣我們發現 \({pj\over q}\) 取遍 $d^{0} $ ~ \(d^{b-1}\) 的倍數
\(d\nmid p , d\nmid q\) : 這樣我們發現 \({pj\over q}\) 為 \(d^{b}\) 的倍數
(3)
proof:
其實就相當於求 1~n 每個數的因子和,變成了求每個數乘上它在 1~n 中被整除的次數
15.
無向連通圖計數:
考慮令 f(n) 為 n 節點無向圖個數, g(n) 為 n 節點無向連通圖個數,則有:
然后...可以考慮 \(n^2\) 遞推,也可以分治 FFT ,甚至還可以考慮更加高級的做法...貌似說還可以對 f 函數取個 ln 就行了?雖說驗證了一下好像鍋了
16.
一個 k 棵樹的森林,邊集為 T , 每棵樹點數為 \(a_i\) ,那么包含邊集 T 的生成樹數量為:
proof:
Prufer 序列感性理解一下?首先每個葉子聯通塊連向另一個聯通塊,我們把連向的聯通塊中節點編號記錄下來,那就是總共搞 k-2 次 , 並且我們每次葉子聯通塊連出去的節點編號並不確定,這樣的 k-2 個葉子節點相乘,在枚舉最后兩個節點相連的那兩個編號,正好是每個聯通塊內的節點數都乘了起來
17.
恆等式:
Proof:
正難則反,我們把后面的式子合起來:
非常暴力...
18.
恆等式,法法塔(FFT)相關:
\(\omega\) 表示單位根, \(\omega_k\) 表示 k 次單位根,則:
Proof:
分類討論:
- \(k\nmid n\)
- \(k\mid n\)
合並一下就是原來的恆等式了
19.
自適應辛普森了解一下
20.
歐拉公式:對於一個任意維度的多面體,存在一下關系
V 表示多面體點數(Vertex)
E 表示多面體邊數(Edge)
F 表示多面體面數(Flat)
proof:
從四面體開始, \(V=4,E=6,F=4\) ,結論成立
然后假設 n 面體滿足公式,那么有:
然后我們發現由三個式子可以合並得到:
21.
三元環計數:
對於一個無向圖,我們可以對它的邊重定向,然后三元環計數
具體方法如下:
- 對於所有的邊,強制度數大的點指向度數小的,度數相等則編號大指向編號小
- O n 處理所有的點,對於點 u ,讓其向連出去的點 v 打上 'u' 的標記
- 對於點 u ,再次掃一遍連出去的點 v ,然后 v 去掃描連出去的點,每次碰到打過 'u' 標記的點就讓 ans++
- 這樣得到的 ans 就是不算重的原圖三元環個數
復雜度的話是 \(O(m\sqrt m)\) , m 為邊數 , n 為點數且 n、 m 同階,下面證明統一用 m
proof:
對於每個點 v 我們分兩種情況:
\(deg_v<\sqrt m\) : 這樣的點最大掃描次數 O(m) ,乘上出度,復雜度 \(O(m\sqrt m)\)
\(deg_u>\sqrt m\) : 這樣的點最多 $\sqrt m $ 個,所以連進來的點也最多根號個,三個根號乘起來,復雜度 \(O(m\sqrt m)\)
綜上,這個算法總復雜度為 \(O(m\sqrt m)\)
22.
環的染色方案數:
我們現在要對一個環進行染色,要求相鄰的點顏色不同,設點的個數為 n,顏色個數為 c,求方案數
設 \(f_i\) 表示 i 個點的染色方案數。我們可以欽定一個開頭,設為 1,並順時針一次記為 2,3,...,n ,那么有:
如果 1 號點和 n−1號點顏色不同,那么方案數為 \(f_{n-1}\),n號點可以選的方案數就是 (c−2)
如果 1號點和 n−1號點顏色相同,那么方案數為 \(f_{n-2}\),即等價於 n−2個點的環再插一個進去,此時 n號點的顏色方案數為 c−1
所以我們可以求得遞推公式
初值為 \(f_0=1,f_1=c\)
根據數列的特征方程(明天要去問數學老師了,問董了的話就 update 上來),我們可以求得 \(f_n\) 的通項公式為
順帶一提,如果需要如果強制環的兩個端點相同的話,方案顯然就是 \(f_{n-1}\)
update:
上面講了特征方程,這玩意兒數學老師說原理比較玄學(雖說看了看推導不是很復雜...),然后叫我自己找資料去
不過還是學到了特征方程的構造方法(不過要線性齊次遞推就是了):
首先根據遞推式列方程,用遞推式里面每一項和最低項的位數差當做該項的次數,舉個例子,如果某個數列的遞推式是這樣的:
那么這個數列的特征方程就是:
然后我們要做的就是解出這個方程的根(\(x_1,x_2,x_3\)),然后得到這么個通項公式:
至於這里的 A, B, C 具體值是多少就要帶入數列的前 3 項解多元一次方程了...
(看您這么聰明舉了這么個例子應該能搞懂了吧?)
具體特征方程是怎么來的和等比數列的轉換有關,具體可以康這里
不過知乎上也有線性代數的說法(可能這個就是本質了?),給個鏈接就逃...(第二個答案)
23.
\(n^2\) 的 Ln 和 Exp (十分好寫...)
推導如下:
Ln
求 \(F(x)=Ln(A(x))\) ,就是對於 A 求個導數求個逆然后相乘,本質就是:
我們讓 \(T(x)=A(x)-1\) , 也就是丟了個常數項,那么 \(A(x)=T(x)+1\) ,且 T(x) 常數項為 0
式子中部極其...emmm,總之別看上面的式子是左右都有 F(x) ,我們可以卷積的嘛,計算某一項系數的時候只需要 O(n) 卷個 \(F(x)T(x)\) ,卷 \(0\)~\(n-1\) 就 好了,因為 T(x) 的 0 次項是 0 啊...
Exp
然后就是 Exp 了,推導很簡單,求個導...
完了咱繼續 O(n) 卷,這回我們就是直接對左邊算 n-1 次項了,所以右邊 F(x) 也卷到 n-1 次就好了,然后我們拿左邊算出的 n-1 項當 F(x) 的第 n 項,至於最低位(常數項)就是 1 了...
代碼僅供參考...
//by Judge
#include<cstdio>
#include<cstring>
#include<iostream>
#define Rg register
#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i)
using namespace std;
const int mod=998244353;
const int M=1e5+3;
typedef int arr[M];
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int dec(int x,int y){return (x-=y)<0?x+mod:x;}
inline int inc(int x,int y){return (x+=y)>=mod?x-mod:x;}
inline int read(){ int x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} char sr[1<<21],z[20];int CCF=-1,Z;
inline void Ot(){fwrite(sr,1,CCF+1,stdout),CCF=-1;}
inline void print(int x,char chr=' '){
if(CCF>1<<20)Ot();if(x<0)sr[++CCF]=45,x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++CCF]=z[Z],--Z);sr[++CCF]=chr;
} int n; arr A,B,inv;
inline void poly_Ln(int* A,int* B,int n){
--A[0];
fp(i,0,n-1){ B[i]=0;
fp(j,0,i) B[i]=inc(B[i],mul(A[i-j],B[j]));
B[i]=dec(mul(A[i+1],i+1),B[i]);
}
fd(i,n-1,1) B[i]=mul(B[i-1],inv[i]);B[0]=0;
}
inline void poly_Exp(int* A,int* B,int n){
fp(i,1,n-1) A[i-1]=mul(A[i],i);
A[n-1]=0,B[0]=1;
fp(i,0,n-1){ B[i+1]=0;
fp(j,0,i) B[i+1]=inc(B[i+1],mul(A[i-j],B[j]));
B[i+1]=mul(B[i+1],inv[i+1]);
}
}
int main(){ n=read(),inv[0]=inv[1]=1;
fp(i,2,n) inv[i]=mul(mod-mod/i,inv[mod%i]);
fp(i,0,n-1) A[i]=read();
poly_Ln(A,B,n);
fp(i,0,n-1) print(B[i]); sr[CCF]='\n';
poly_Exp(A,B,n);
fp(i,0,n-1) print(B[i]); sr[CCF]='\n';
return Ot(),0;
}
24.
凸多邊形、凸多面體的重心計算:
多邊形
對於三角形的重心計算,只需要對於三角形三個頂點 \((x_1,y_1),(x_2,y_2),(x_3,y_3)\) 進行累加除三就好了,即重心 \(G({x_1+x_2+x_3 \over 3} ,{y_1+y_2+y_3\over 3})\)
先對原圖形三角剖分,然后求出每個三角形對應的重心(就用上面的三角形重心計算公式)
然后對於所有的三角形,我們對於橫坐標和縱坐標分別處理,即總重心橫坐標為:\(\sum_i x_i · m_i\over \sum_i m_i\) ,這里的 \(m_i\) 表示質量,學過高中物理老師可能講過,但是在這里就代表面積了,至於總重心的縱坐標也可以用類似的方法求出,那么用 \(a_i\) 表示第 i 個三角形的坐標,總重心坐標即是:
簡單的說,這里的 質量 \(m_i\) 就是面積 \(s_i\) :
多面體
類比一下,凸多面體的重心求解大概就是:
對於四面體的重心計算,我們只需要把四個頂點的橫縱坐標分別加起來除去四就一一對應了重心的橫坐標和縱坐標,即:\(x_G={x_1+x_2+x_3+x_4\over 4},y_G={y_1+y_2+y_3+y_4\over 4}\),四面體質量(這里即體積)的計算就各憑本事了
先對於多面體四面體剖分,然后求出每個四面體的重心
接着進行類似凸多邊形的處理,把所有的坐標乘上質量,相加除去總質量即可,公式如下(和上面那個差不了多少):
其中 \(v_i\) 表示體積
PS:多嘴一句,這里的坐標其實看做多維向量就好了(學過線代的大佬們表示秒出...)
25:
求解二面角:
其實(搞信息的)並不怎么用?
要求給出兩個平面求出兩個平面之間的夾角(當然,兩個平面相交...)
做法就是先建個系(一般來講題目里面要給出平面的話其實就是給出了三維坐標系),然后我們要求出兩個平面分別的法向量(這里的法向量也就是跟原平面垂直的一個三維向量),法向量求法如下:
設坐標\((x_0,y_0,z_0)\),然后在平面上隨便找兩條不相交的向量,然后兩個向量叉乘就可以得到一個該平面的法向量(求法參照線性代數)
然后我們對於兩個平面的法向量求個三角函數值,再反三角函數轉回來就好了:
(下面那倆玩意兒就是數值相乘)
然后反三角函數直接上?
26.
點到直線距離:
兩平行直線距離:
27.
曼哈頓距離 和 切比雪夫距離 的定義及相互轉換:
定義
對於兩個點 \((x_i,y_i),(x_j,y_j)\) ,他們的
曼哈頓距離的定義:
\[dis_{h(i,j)}=|x_i-x_j|+|y_i-y_j| \]
切比雪夫距離的定義:
\[dis_{q(i,j)}=max(|x_i-x_j|,|y_i-y_j|) \]
轉化:
那么他們之間的轉化有二(其實就是互相轉化):
把原坐標 \((x,y)\) 轉化為 \((x+y,x-y)\) ,那么原本坐標系中的曼哈頓距離就是轉化后的坐標系中的切比雪夫距離
把原坐標 \((x,y)\) 轉化為 \(({x+y\over 2} , {x-y\over 2})\) ,那么原本坐標系中的切比雪夫距離就是轉化后的坐標系中的曼哈頓距離
我們可以發現這兩個轉化是互逆(等價)的,也就是說證明其中一個成立,則另一個命題也成立,那么我們不妨就證明第一個轉化的正確性好了:
我們把設 原坐標為 \((x,y)\) ,新坐標為 \((x',y')=(x+y,x-y)\) ,那么有:
為了式子更加簡潔,我們令 \(X=x_i-x_j,Y=y_i-y_j\)
證畢...
28.
笛卡爾定理
設四個圓的半徑為: \(r_1,r_2,r_3,r_4\),
1、若四個圓兩兩外切,則有:
2、若前三個圓兩兩外切,且都內切於第四個圓,則有:
具體的證明...據說是用韋達定理?
如果是三維的五個球的話,定理也與上面類似,分為外切內切兩種情況
應該還可以拓展到更高的維度...
29.
階梯博弈:
有 n 級台階,每級上都有一定的石子。每次可以把一個階梯的石子往下移,0級階梯的不能移,不能操作者輸。
首先偶數層是不會有任何影響的,因為如果你移動偶數層若干個石子到奇數層,那么對手一定可以通過移動把你移的石子移到下一個偶數層,相當於這些石子仍然在偶數層。那么我們只需考慮奇數層的石子
所以我們可以把原問題變為取走奇數層的石子,無法操作者失敗
那么這就是 Nim 游戲了
30.
若 \(i,j \in [1,n]\) 那么有:
一、$E(max(i,j))=O({2\over3} n) $
二、\(E(|i-j|)=O({1\over 3}n )\)
對於第一個結論,我們考慮暴力證明
對於第二個結論,我們同樣考慮暴力證明
其實對於第二個結論,可以近似看做線段上隨機取兩個點,兩點之間長度的期望值為線段總長的 \({1\over 3}\),同時這也是珂朵莉樹算法的理論基礎(關鍵數據得是隨機滴...)
31.
一些多項式展開:
32.
巴什博奕
這玩意兒挺有趣的...雖說自己不會證
背景就是有 \(n\) 個石子,每次最多取 \(m\) 個,不能操作(即石子已被取光)者失敗。
結論就是先手不面臨 $n=k(m+1),k\in N^* $ 的情況就必勝
我們歸納一下證明:
當 \(n<=m\) 時,先手全取光,就贏了
當 \(n=m+1\) 時,先手只能取 \([1,m]\) 范圍內的石子個數,剩下的石子數必然在 \([1,m]\) 范圍中,這樣后手就面臨了第一種情況,必勝
對第二個結論推廣一下,當 $n=k(m+1),k\in N^* $ 時,先手無論怎么取,剩下的石子數都是: \(k(m+1)+r,k\in N^* , r<m+1\) ,這樣后手只需取走 \(r\) 個石子,情況就回到了之前的情況,這樣的情況持續下去直到 \(k=1\) ,那么就變成了第二種情況,后手必勝
那么對第三個結論換個角度看看,如果說 \(n=k(m+1)+r,k\in N^* , r<m+1\) 的話,先手取走 \(r\) 個石子,回到第三種情況,先手必勝
總結一下,只要 $n\not=k(m+1),k\in N^* $ ,先手必勝,反之后手必勝
代碼...這不是顯然么...