您的位置:首页 > 其它

jzoj5317 【清华集训2017模拟8.19】func (寻找性质)

2017-08-20 22:57 543 查看

题意



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)互质 (归纳法).

这个过程类似欧几里得,我们设f(g(a,b))=a,f(g(a,b)+1)=b。

分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
,d
[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
;
int mi
;
int xg
,xc
;

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]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: