题意
n<=1e6
分析
做比赛的时候啥也没看出来..
求
f(x)=n
的所有x,我们先将函数的定义式分析一下。
f(2i)=f(i)
f(2i+1)=f(i)+f(i+1)
两个相邻的f也是由两个相邻的f推来的。那么我们不如枚举
f(x−1)=i
,然后发现可以确定唯一的
x
。需要注意的是相邻f(x)互质 (归纳法).
这个过程类似欧几里得,我们设
分a < b与a > b两种情况讨论一下,显然哪边大哪边就是奇数。
然后考虑如何将“更相减损“变成“辗转相除“。
直接根据原有性质优化就行了,比较简单吧。
demo
1 更相减损
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1e6+10,mo=998244353;
int n,ans[N],d[N][2];
int gcd(int x,int y) {return y?gcd(y,x%y):x;}
int g(int a,int b) {
if (a==1 && b==1) return 1;
int xx=0;
if (a<b) {
xx=g(a,b-a);
return xx*2%mo;
} else {
xx=g(a-b,b);
return (xx*2+1)%mo;
}
}
int main() {
freopen("func.in","r",stdin);
freopen("func.out","w",stdout);
cin>>n;
for (int i=1; i<=n; i++) if (gcd(i,n)==1) {
int x=g(i,n);
ans[++ans[0]]=x+1;
}
sort(ans+1,ans+1+ans[0]);
for (int i=1; i<=ans[0]; i++) printf("%d\n",ans[i]);
}
2 辗转相除
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+10,mo=998244353;
int n,ans[N];
int mi[N];
int xg[N],xc[N];
int gcd(int x,int y) {return y?gcd(y,x%y):x;}
int g(int a,int b) {
if (a==0 || b==0) return 1;
int xx=0;
if (a<b) {
int cnt=(b-1)/a+1;
xx=g(a,b%a);
return (ll) xx*mi[cnt-1]%mo;
} else {
int cnt=(a-1)/b+1;
xx=g(a%b,b);
return ((ll) xx*mi[cnt-1]%mo+mi[cnt-1]-1)%mo;
}
}
int main() {
freopen("func.in","r",stdin);
// freopen("func.out","w",stdout);
cin>>n;
mi[0]=1; for (int i=1; i<=n; i++) mi[i]=(ll) mi[i-1] * 2%mo;
for (int i=1; i<=n; i++) if (gcd(i,n)==1) {
int x=g(i,n);
ans[++ans[0]]=x+1;
}
sort(ans+1,ans+1+ans[0]);
for (int i=1; i<=ans[0]; i++) printf("%d\n",ans[i]);
}