D. Frog Jumping(裴蜀定理bfs)
Posted Lnn.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D. Frog Jumping(裴蜀定理bfs)相关的知识,希望对你有一定的参考价值。
前言:有趣的数论题 (因为表达式少写括号多d了一个小时的bug(晕
题目传送门
题目类型:数论、裴蜀定理、bfs
解析:先说一个结论,当n小于a+b时直接bfs;>=a+b时所有点x == k*gcd(a,b)都能到达。
bfs部分不说了,很基础。
设青蛙向右跳跃x次,向左y次,到达了n,对于青蛙的跳跃轨迹,可以用一个方程表达:ax + by = n。
这个式子就很难不想到裴蜀定理:a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)。
所以青蛙能够到达的点一定是g = gcd(a,b)的倍数。
写题的时候随便画了一下,发现n >= a+b时所有g的倍数都能够到达,感性证明一下:
g = gcd(a,b) 。
由裴蜀定理,一定存在ax - by == gcd(a,b),并且x>0。由于题目要求当前位置要一直大于等于0,对于x,y我们可以这样分配:当位置>=b时,尽量回撤,当<b时,只能向前走。此时最远会走到 b-1 + a。所以只要给出a+b的空间,就一定能走到gcd(a,b)的地方,重复这个过程k次,就能走到k*gcd(a,b)的地方。
code:
void bfs(ll x , ll r)
vis[x] = 1;
++now;
if(x + a <= r && !vis[x+a])bfs(x+a,r);
if(x - b >= 0 && !vis[x-b])bfs(x-b,r);
void solve()
ll ans = 0;
now = 0;
g = gcd(a,b);
ll aim = a+b-1;
for(ll i = 0 ; i <= aim ; ++i)
if( i == 0 || (i >= a && vis[i-a]) )
bfs(i,i);
ans += now;
if(i == n)
cout << ans << endl ;
return;
ll l = aim+1 , r = n;
ans += (r-l+1); ///补上0点的
if(l/g == r/g)
ans += (r-l+1) * (l/g);
else if(l/g + 1 == r/g)
ans += (r - r/g*g + 1) * (r/g);
ans += ((l/g+1)*g - l) * (l/g);
else
ans += (r - r/g*g + 1) * (r/g);
ans += ((l/g+1)*g - l) * (l/g);
l = l/g*g + g;
r = r/g*g - 1;
ans += (l/g*g + r/g*g) * (r/g - l/g + 1)/2;
cout << ans << endl ;
以上是关于D. Frog Jumping(裴蜀定理bfs)的主要内容,如果未能解决你的问题,请参考以下文章
D. Not Quite Lee(裴蜀定理gcdlowbit)
D. Not Quite Lee(裴蜀定理gcdlowbit)
D. Not Quite Lee(裴蜀定理gcdlowbit)