2024.3.31 【人间骄阳刚好,风吹过树梢,彼时他们正当年少——某某】
Sunday 二月二十二
<BGM = 那年·年少 - 宋宇宁>
<theme = oi-“search”>
来看道典题
P1763 埃及分数
//2024.3.31
//by white_ice
#include<bits/stdc++.h>
using namespace std;
#define itn long long
#define int long long
const int oo = 10000007;
int jgby(int a,int b){while(b^=a^=b^=a%=b);return a;}
int ngm (itn a,itn b){return a<b?a:b;}
itn jntm(itn a,itn b){return a>b?a:b;}
int a,b,madis;
int out[oo],st[oo];
int s;
bool dfs(itn a,itn b,int dis){
if (dis == madis){
if (a==1&&b>st[dis-1]&&(b<out[dis]||!out[dis])){
st[dis] = b;
memcpy(out,st,sizeof(st));
return true;
}
return false;
}
if (dis == madis - 1){
for (itn z=(b<<2)/a/a+1;z<ngm((s<<1)/a,s*s/a);z++){
itn d = a*a*z*z-(b<<2)*z;
itn s = sqrt(d);
if (s*s!=d||a*z+s&1)
continue;
st[dis] = a*z-s>>1;
st[dis+1]=a*z+s>>1;
if (st[dis+1]<out[dis+1]||!out[dis+1]){
memcpy(out,st,sizeof(st));
return true;
}
}
return false;
}
itn l = jntm(st[dis-1],(b-1)/a)+1LL;
int r = (madis-dis+1)*b/a;
bool flag = 0;
for (int i=l;i<r;i++){
itn tx = a*i-b,ty = b*i;
itn g = jgby(tx, ty);
st[dis] = i;
if (dfs(tx/g,ty/g,dis+1))
flag = 1;
}
return flag;
}
signed main (){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin >> a >> b;
bool tag = 0;
while (!tag){
s = 100;
madis++;
while (s<1e7&&!tag)
s = (s<<3)+(s<<1),tag = dfs(a,b,1);
}
for (itn i=1;i<=madis;i++)
cout << out[i] << ' ';
return 0;
}
本题使用了iddfs,也就是迭代加深搜索。
通过每次设定一个预期的dis,也就是预定深度,再依据此深度为限制进行搜索。
本代码中设为madis。
当搜索致dis = madis - 1时,若剩余分数仍久分子不为一,则剪枝优化掉。
下面推一下柿子:
$$
\frac{a}{b} = \frac{1}{x}\ + \ \frac{1}{y}\
\left{
\begin{aligned}
az = x+y\
bz = xy
\end{aligned}
\right.
\rArr
x^2\ - \ azx\ - \ bz \ =\ 0
$$
也就是:
x
=
a
z
−
Δ
2
y
=
a
z
+
Δ
2
x\ = \ \frac{az\ - \ \sqrt{\Delta}}{2}\\ y\ = \ \frac{az\ + \ \sqrt{\Delta}}{2}
x = 2az − Δy = 2az + Δ
柿子非常好看啊。
只要证明一下$ \Delta $能够被整开就行。
然后就代码就行。