Floyd Tortoise and Hare & 環檢測算法

參考:Floyd判圈算法理解
參考:Floyd判圈算法(龜兔賽跑算法, Floyd’s cycle detection)及其證明
參考:Floyd’s Tortoise and Hare & 環檢測算法


簡介

Floyd判圈算法(Floyd Cycle Detection Algorithm),又稱龜兔賽跑算法(Tortoise and Hare Algorithm)。該算法由美國科學家羅伯特·弗洛伊德發明,是一個可以在有限狀態機、迭代函數或者鏈表上判斷是否存在環,求出該環的起點與長度的算法。

檢測一個鏈表是否有環(循環節),如果有,確定環的起點以及環的長度


複雜度

時間複雜度:O(n+m)O(n+m)
空間複雜度:O(1)O(1)
nn 爲起點 SS 到環入口 PP 的距離,mm 爲環的長度


結論

  :環檢測
  兩個指針 tthhtt 移動速度爲 11hh 移動速度爲 22,判斷是否相遇

  :找出環的入口節點
  兩個指針相遇後,將 tt 重新放到鏈表頭,然後兩個指針速度都爲 11,再次相遇後,所在位置即爲入口節點

  :計算環長度
  兩個指針都放在入口節點後,tt 移動速度爲 11hh 移動速度爲 00,再次相遇,即可計算出環長度


例題: H. Pseudo-Random Number Generator

在這裏插入圖片描述

計算入口節點及環長度:

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = (1ll << 40);
inline ll nxt(ll x){
	return (x + (x >> 20) + 12345ll) % mod;
}

signed main() {
	ll s0 = 0x600DCAFE, cnt = 0, num = 0;
	ll t = s0, h = s0;
	while(true){
		t = nxt(t), h = nxt(nxt(h));
		++cnt;
		if(!(t & 1)) ++num;
		if(t == h) break;
	}
	
	t = s0, cnt = num = 0;
	while(true){
		t = nxt(t), h = nxt(h);
		++cnt;
		if(!(t & 1)) ++num;
		if(t == h) break;
	}
	ll st_cyc = cnt, st_num = num;
	
	cnt = num = 0;
	while(true){
		t = nxt(t);
//		h = nxt(h);
		++cnt;
		if(!(t & 1)) ++num;
		if(t == h) break;
	}
	ll len_cyc = cnt, ans_cyc = num;
	
	deb(st_cyc); deb(st_num); 
	puts("-----------");
	deb(len_cyc); deb(ans_cyc);
}

分塊打表處理答案:

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1ll << 40;
const int base = 5e6;
inline ll nxt(ll x){
	return (x + (x >> 20) + 12345ll) % mod;
}

ll mat[1010][2] = {
	1611516670, 1,
	6995323118, 2500401,
	14370630249, 5004364,
	24473902285, 7500029,
	38312556854, 10006017,
	57274551969, 12506329,
	83248007737, 15011683,
	118826730177, 17517443,
	167560289742, 20012408,
	234323188514, 22530434,
	325792323073, 25031296,
	451094609069, 27539195,
	622741727028, 30040232,
	857898708083, 32538480,
	937685173, 35042602,
	6072677726, 37541450,
	13107744445, 40042828,
	22744003927, 42546233,
	35943646365, 45056959,
	54027907086, 47548216,
	78802032994, 50056831,
	112739509636, 52565704,
	159235062884, 55056278,
	222913708970, 57559660,
	310147760736, 60057168,
	429642460847, 62554179,
	593348380684, 65062411,
	817588294774, 67574933,
	295498034, 70077204,
	5192879414, 72572034,
	11901289737, 75074286,
	21092425584, 77586589,
	33681877906, 80089334,
	50930014590, 82577797,
	74557367833, 85076566,
	106926639410, 87569837,
	151258698876, 90060817,
	211997026857, 92557144,
	295206930517, 95067617,
	409189858068, 97582000,
	565345893787, 100089173,
	779223572048, 102578453,
	1072246754882, 105080524,
	4354683110, 107578420,
	10752858133, 110081437,
	19518274761, 112579315,
	31526697331, 115071718,
	47977804257, 117584728,
	70512631458, 120091493,
	101383583168, 122603663,
	143677078963, 125100277,
	201601781662, 127598938,
	280954761586, 130104566,
	389678281232, 132606644,
	538598461112, 135114812,
	742592321221, 137604957,
	1022070324749, 140110603,
	3554026557, 142613775,
	9655697881, 145118771,
	18014204912, 147616701,
	29466792348, 150119937,
	45154383935, 152614526,
	66642984633, 155117508,
	96085200428, 157608613,
	136417233148, 160106698,
	191671943332, 162605678,
	267368060404, 165108248,
	371063286307, 167605345,
	513107125545, 170101751,
	707668644954, 172599641,
	974225187667, 175085228,
	2790547793, 177572982,
	8611289031, 180074324,
	16584933110, 182564868,
	27507640334, 185067560,
	42470755600, 187569610,
	62966213954, 190070901,
	91040988045, 192573754,
	129505250351, 195073010,
	182194153727, 197571938,
	254367017868, 200067363,
	353236621546, 202571441,
	488691710416, 205056578,
	674235835123, 207563824,
	928397275086, 210056612,
	2061291639, 212555608,
	7611195984, 215046440,
	15215211602, 217558986,
	25631359205, 220055532,
	39898870311, 222551803,
	59446145748, 225059431,
	86223613511, 227563092,
	122903535528, 230050444,
	173156136173, 232565955,
	241996682198, 235069888,
	336303276921, 237573994,
	465478252203, 240074925,
	642434794044, 242579118,
	884883721897, 245073898,
	1367467361, 247575267,
	6660774750, 250065868,
	13913445317, 252566347,
	23846914106, 255061631,
	37457188797, 257561860,
	56101519545, 260064780,
	81642081850, 262557086,
	116629560400, 265048248,
	164557000612, 267539163,
	230202910861, 270039390
};

void pre() {
	ll x = 0x600DCAFE, ans = 1;
	printf("%lld,%lld,\n", x, 1);
	for (ll i=1; i<=542254520; ++i) {
		ll y = nxt(x);
		if (!(y & 1)) ans++;
		if (i % base == 0) printf("%lld,%lld,\n", y, ans);
		x = y;
	}
}

int main() {
	ll st_cyc = 350125311;
	ll ans_cyc = 91029304;
	ll len_cyc = 182129209;
	
	ll n, ans;
	scanf("%lld", &n); n--;
	if (n <= st_cyc) {
		ans = mat[n / base][1];
		ll s = mat[n / base][0];
		for (ll i = n / base * base + 1; i<=n; ++i) {
			ll x = nxt(s);
			ans += !(x & 1);
			s = x;
		}
		if(n == -1) ans = 0;
		return printf("%lld\n", ans), 0;
	}
	
	ans = (n - st_cyc) / len_cyc;
	n -= ans * len_cyc;
	ans *= ans_cyc;
	ans += mat[n / base][1];
	ll s = mat[n / base][0];
	for (ll i = n / base * base + 1; i<=n; ++i) {
		ll x = nxt(s);
		ans += !(x & 1);
		s = x;
	}
	printf("%lld\n", ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章