傷寒雜病論


持續更新 Gu~

大概是雜文集吧

以下是目錄:

0. 集合

1. 光速冪(\(k\) 進制倍增)

\(a, p\) 一定,求

\[a^x \bmod p \]

1. 朴素

基本的歐拉降冪就不說了,可以將 \(x\) 縮小到 \(\varphi(p)\le p\) 的范圍內 .

考慮分塊預處理,令 \(r = \lfloor\sqrt p\rfloor\),則我們可以把 \(a^x\) 分成幾個整塊的 \(a^r\) 和一個散的

預處理 \(a^r, (a^r)^2, (a^r)^3, \cdots, , (a^r)^r\)\(a, a^2\cdots, a^r\),然后我們就可以求 \(a^x\)

\[a_x = a^{rp + q} = (a^r)^p\cdot a^q \]

這里 \(rp+q\) 類似一個帶余除法,\(0\le q < r\) .

這樣空間復雜度 \(O(\sqrt p)\),時間復雜度 \(O(\sqrt p) - O(1)\)

這玩意還可以用類似方法搞搞擴域光速冪,矩陣光速冪啥的 .

Code:

template<int MOD>
struct FastPow
{
private:
	ll p1[66666],p2[66666];
	static ll qpow(ll a,ll n)
	{
		ll ans=1;
		while (n)
		{
			if (n&1) ans=ans*a%MOD;
			a=a*a%MOD; n>>=1;
		} return ans%MOD;
	}
public:
	explicit FastPow(ll a)
	{
		ll t1=a,t2=qpow(t1,65536); p1[0]=p2[0]=1;
		for (int i=1;i<65536;i++) p1[i]=p1[i-1]*t1%MOD;
		for (int i=1;i<65536;i++) p2[i]=p2[i-1]*t2%MOD;
	}
	ll operator()(unsigned n){return p2[n>>16]%MOD*p1[n&65535]%MOD;}
};

例題:塊速遞推

2. 不朴素

我們這個 \(r\) 也不一定取 \(\sqrt p\) .

類似快速冪,我們拆

\[a^x = a^{x\bmod k}\cdot (a^k)^{\lfloor x/k\rfloor} \]

左邊預處理,右邊遞歸做 .

這一般被叫做 \(k\) 進制倍增,當 \(k=2\) 時等價於快速冪 .

這個可以用來調節預處理復雜度和詢問復雜度,例如 \(r\)\(p^{1/3}\) 時 .

空間復雜度 \(O(k\log_k p)\) 時間復雜度 \(O(k\log_k p) - O(\log_k p)\)(有錯望指正).

例題:能量采集

2. 在線離散化

就是一個小工具 .

一個全自動 Hash 器,挺好用,可以讓你避免離散化化化化化化

template<typename T>
struct pool
{
	unordered_map<T, unsigned> pol;
	unsigned cc = 0;
	unsigned get(T x)
	{
		auto ptr = pol.find(x);
		if (ptr == pol.end()){pol[x] = ++cc; return cc;}
		else return ptr -> second;
	}
};

例:程序設計分析 AC 代碼(提交記錄

using namespace std;
const int N = 1e6 + 500;
typedef long long ll;
int fa[N], n;
inline void init(int n){for (int i=0; i<=n; i++) fa[i] = i;}
int fnd(int x){return (fa[x] == x) ? x : fa[x] = fnd(fa[x]);}
void merge(int u, int v){fa[fnd(u)] = fnd(v);}
struct pool
{
	unordered_map<int, int> pol;
	int cc = 0;
	int get(int x)
	{
		auto ptr = pol.find(x);
		if (ptr == pol.end()){pol[x] = ++cc; return cc;}
		else return ptr -> second;
	}
}T;
void _()
{
	init(1e6);
	scanf("%d", &n);
	vector<pair<int, int> > query;
	for (int u, v, opt, i = 0; i<n; i++)
	{
		scanf("%d%d%d", &u, &v, &opt);
		if (opt == 1)
		{
			int U = T.get(u), V = T.get(v);
			merge(U, V);
		}
		else query.push_back(make_pair(u, v));
	}
	for (auto x : query)
	{
		int u = x.first, v = x.second, U = T.get(u), V = T.get(v);
		if (fnd(U) == fnd(V)){puts("NO"); return ;} 
	} puts("YES");
}
int main()
{
	int T; scanf("%d", &T);
	while (T--) _(); // solve
	return 0;
}

3. 鄰接表

好像目前沒啥應用

就是把鄰接表鏈的鏈表改成別的數據結構,比如改成平衡樹 / SkipList 就可以支持刪邊 .

4. C-Style 字符串小結

常見函數

  • strlen 長度
  • strcmp 比較(strcmpi 不區分大小寫)
  • strcpy 復制
  • strcat 追加
  • strrev 字符串反轉
  • strupr 轉大寫

全文讀取:

void rdfile(const char* a)
{
	char* ptr=a;
	while ((*ptr=getchar()) && (*ptr!=EOF)) ++ptr;
}

5. 信息傳遞的一點研究

0. 一些小前置

\(\mathsf D_1\) 基環樹是啥?link . 基環內向樹是啥?所有邊的方向都向着環的方向的基環樹 .

\(\mathsf D_2\) 弱聯通是啥?有向圖去掉方向后的連通性


\(\mathsf P\)

維護一個序列 \(a\),支持

  1. 區間循環移 \(x\)
  2. 區間加
  3. 單點查

一次 \(1\) 操作拆成三次區間 reverse,用文藝平衡樹即可 \(O(\log n)\),於是 \(3\) 可以用 tag 做到 \(O(\log n)\)\(2\) 可以遞歸 \(O(\log n)\)

1. 朴素信息傳遞

題面大概是

給一個基環內向樹森林求最小環

仨經典算法

  • 並查集
  • 拓撲排序
  • tarjan

一些別的算法

  • dfs,用並查集標記弱聯通
  • Floyd 判圈法

2. 帶修信息傳遞

題面大概是

給一個基環內向樹森林求最小環

每次修改將 \(u\to v_0\) 的邊刪掉,改成 \(u\to v_1\) .

現在除掉方向 .

從環上按順序把每棵樹的 DFS 序拼起來就當作整個森林的 DFS 序 .

維護 DFS 序的過程就是前置 \(\mathsf P\),區間加維護每個點到環的距離,就可以維護環長了 .

預處理 \(O(n)\),修改 \(O(\log n)\),哈哈 .

或許可以 Euler Tour Tree??

假了請告訴我並爆 D 我的算法 qwq

upd: 這玩意其實叫 深度確定問題 .

upd:不是 depth determination,不能並查集,只能 \(\log\) 平衡樹 .


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM