题解 斐波那契

传送门

考场上找半天规律没找出来。。。

其实规律可以根据题解推出来:
令一个父亲节点的标号为\(j\)
考虑它在第i代所生的孩子,此时已有\(fib[i-1]\)只兔子,其中标号\(\leqslant fib[i-2]\)的兔子能生育
所以它在这一代的孩子为标号为\(fib[i-1]+j\)
那就可以逆推,一个标号减去严格小于它的第一个斐波那契数所得,即为其父亲标号
所以可以暴力上翻了。
不建议试图对斐波那契数建树并利用倍增优化过程,这样需要加极多特判别问我怎么知道的

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000100
#define ll long long 
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long 

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline ll read() {
	ll ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans;
}

int m;

namespace force{
	int lim, size=1;
	int head[N], esiz, fa[N][25], dep[N], lg[N];
	bool vis[N];
	struct que{ll a, b; inline void build(int k, int j) {a=k; b=j;}}que[N];
	queue<int> q, q2;
	
	int lca(int a, int b) {
		if (dep[a]<dep[b]) swap(a, b);
		while (dep[a]>dep[b]) a=fa[a][lg[dep[a]-dep[b]]-1];
		if (a==b) return a;
		for (int i=lg[dep[a]]-1; i>=0; --i) 
			if (fa[a][i]!=fa[b][i]) 
				a=fa[a][i], b=fa[b][i];
		return fa[a][0];
	}

	void solve() {
		int t;
	
		m=read();
		for (int i=1,a,b; i<=m; ++i) {
			a=read(); b=read();
			lim=max(lim, max(a, b));
			que[i].build(a, b);
		}
		for (int i=1; i<=lim; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
		dep[1]=1; q.push(1);
		while (size<=lim) {
			//cout<<size<<endl;
			t=q.front(); q.pop();
			//cout<<"t: "<<t<<endl;
			if (t==1) while (!q2.empty()) q.push(q2.front()), q2.pop();
			if (!vis[t]) {vis[t]=1; q.push(t); continue;}
			++size;
			//if (t==1) cout<<size<<endl;
			dep[size]=dep[t]+1;
			fa[size][0]=t;
			for (int i=1; i<23; ++i) 
				if (dep[size]>=(1<<i)) fa[size][i]=fa[fa[size][i-1]][i-1];
				else break;
			q.push(t);
			q2.push(size);
		}
		for (int i=1; i<=m; ++i) 
			printf("%d\n", lca(que[i].a, que[i].b)); //, cout<<"lca "<<que[i].a<<' '<<que[i].b<<endl;
	}
}

namespace task{
	ll fib[65];
	
	inline ll find(ll a) {return a-*(lower_bound(fib+1, fib+61, a)-1);}
	void solve() {
		ll a, b, f, frk, af, bf;
		
		m=read();
		fib[0]=fib[1]=fib[2]=1;
		for (int i=3; i<=60; ++i) fib[i]=fib[i-1]+fib[i-2];
		//for (int i=1; i<=20; ++i) cout<<fib[i]<<' '; cout<<endl;
		for (int i=1; i<=m; ++i) {
			a=read(); b=read();
			if (a==b) {printf("%lld\n", a); continue;}
			if (a==1||b==1) {puts("1"); continue;}
			while (a!=b) {
				if (a>b) a=find(a);
				else b=find(b);
			}
			printf("%lld\n", a);
		}
	}
}

signed main()
{
	#ifdef DEBUG
	freopen("1.in", "r", stdin);
	#endif
	
	task::solve();

	return 0;
}
posted @ 2021-06-22 16:45  Administrator-09  阅读(27)  评论(0编辑  收藏  举报