您的位置:首页 > 其它

【JZOJ5317】【清华集训模拟】func(辗转相除法、找规律)

2017-08-23 22:48 288 查看

Description



Solution

这是一个可以找规律的题目,但是性质也是比较的好推。

我们可以观察相邻的两项i,i+1,f(i)、f(i+1)的值分别是对应着x、y,然后f(2*i)=x,f(2*i+1)=x+y,f(2*i+2)=y。

然后我们可以发现相邻的两个每次都*2,他们的值也是较小的加上较大的。

那么我们可以倒着推回来,每次值是较大的减较小的,然后判断是左边的较小还是右边的较小,然后判断下标变化的情况。这样更相减损,如果打的好可能可以过。

但是我们知道更相减损是可以打成辗转相除的,遮掩可以在log的时间跑出来。

那么对于询问的值n,我们可以考虑枚举前面的数的值i,对于相邻的值(i,n)肯定只会出现一次。

时间复杂度O(nlogn)

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=1e6+7,mo=998244353;
ll i,j,k,l,t,n,m,ans,a,b;
ll an[maxn],er[maxn];
void dfs(ll x,ll y){
ll t;
if(x==1&&y==1){
a=2;b=1;
return;
}
if(x==y){a=b=-1;return;}
if(x>y){
t=x/y-(x%y==0);
dfs(x-t*y,y);
if(a<0)return;
a=(a+(er[t]-1)*b)%mo,b=er[t]*b%mo;
}
else{
t=y/x-(y%x==0);
dfs(x,y-x*t);
if(a<0)return;
b=(b+(er[t]-1)*a)%mo,a=er[t]*a%mo;
}
}
void write(int x)
{
if (!x) putchar('0');else
{
char s[10];
int i,j=0;
for (;x>0;x/=10) s[j++]=x%10;
for (i=j-1;i>=0;i--) putchar(s[i]+48);
}
putchar('\n');
}
int main(){
freopen("func.in","r",stdin);
freopen("func.out","w",stdout);
//   freopen("fan.out","w",stdout);
scanf("%lld",&n);
er[0]=1;fo(i,1,n)er[i]=er[i-1]*2%mo;
fo(i,1,n){
a=b=0;
dfs(i,n);
if(b>0)an[++an[0]]=b%mo;
}
sort(an+1,an+1+an[0]);
fo(i,1,an[0]){
write(an[i]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: