题目背景

pj组选手zzq近日学会了求最大公约数的辗转相除法。

题目描述

类比辗转相除法,zzq定义了一个奇怪的函数:

typedef long long ll;
ll f(ll a,ll b)
{
if(a==b) return ;
if(a>b) return f(a-b,b+b)+;
else return f(a+a,b-a)+;
}

zzq定义完这个函数兴高采烈,随便输入了两个数,打算计算f值,发现这个函数死循环了...于是zzq定义这个函数递归死循环的情况下f值为0。

现在zzq输入了一个数n,想要求出洛谷P3764 签到题 III-LMLPHP

输入输出格式

输入格式:

一行两个数n。

输出格式:

一行一个数洛谷P3764 签到题 III-LMLPHP

输入输出样例

输入样例#1:

100
输出样例#1:

1124
输入样例#2:

2000
输出样例#2:

68204

说明

对于10%的数据,洛谷P3764 签到题 III-LMLPHP

对于40%的数据,洛谷P3764 签到题 III-LMLPHP

对于70%的数据,洛谷P3764 签到题 III-LMLPHP

对于100%的数据,洛谷P3764 签到题 III-LMLPHP

数学问题 结论题 分块

似乎很有趣。

要证一个奇奇怪怪的结论:

当且仅当 “ $ a/(gcd(a,b)+b/gcd(a,b)=2^m $ ”时, $ f(a,b) $ 值为 $ m-1 $ ,否则 $ f(a,b)=0 $

一种简单的证明如下:

另一种并不严谨的证明如下:

然后愉快(并不)地分块求值。

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define LL long long
using namespace std;
const int mxn=;
LL read(){
LL x=,f=;char ch=getchar();
while(ch<'' || ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>='' && ch<=''){x=x*-''+ch;ch=getchar();}
return x*f;
}
LL n,ans=;
int main(){
n=read();
int lg=;
for(LL i=;i;i<<=){
for(LL x,j=(i>>)+;j<i && j<=n;j=x+){
x=n/(n/j);
x=min(x,min(n,i-));
if(!(x&))x--;
ans+=lg*(n/j)*(((x-j)>>)+);
}
if(i>=n)break;
++lg;
}
ans<<=;
printf("%lld\n",ans);
return ;
}
05-19 09:03