[agc015f]Kenus the Ancient Greek

前言

结论题我只能orz。
题解错了很不舒服。

题意

找到(n,m)以内点对欧几里得步数最大的点对个数。

做法

设f(a,b)表示欧几里得步数。
我们先设斐波那契数 F0=1,F1=1,Fi+2=Fi+1+Fi
容易发现 f(Fk,Fk+1)=k
结论一:如果 f(x,y)=k ,且 x<y ,则一定有 x>=Fk 以及 y>=Fk+1
这个可以用归纳法证明。
然后我们发现,对于 gcd(x,y)>1 如果 f(x,y)>1 这样的(x,y)不会计算入答案。
这个也好证。
于是我们只需要在答案等于1的时候特判,其余情况当然只需要考虑gcd为1的点对。
我们定义如果不存在 x<xy<y使f(x,y)>f(x,y) 那么(x,y)是好的。
显然我们只统计好的点对。
然后我们定义如果 f(x,y)=k x,y<=Fk+2+Fk1 那么(x,y)是优秀的。
结论二:如果(x,y)是好的,那么一步后会变成优秀的。
可以用反证法证明。
然后我们只需要找出所有优秀的点对,就很容易统计答案。
找的方法是用k的得到k+1的。
优秀的点对有多少呢?
在最小的情况下是 (Fk,Fk+1) ,容易发现它只会产生2~3个新的,而其余的则只能产生1个。
因此是log级别的。

#include<cstdio>
#include<algorithm>
#include<vector>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pi;
const int mx=90+10,mo=1000000007;
const ll inf=1000000000000000000;
ll fib[mx];
vector<pi> a[mx];
vector<pi>::iterator it;
ll x,y,n,m,num;
int i,j,k,l,t,tot,ca,ans;
int main(){
    fib[0]=fib[1]=1;
    tot=1;
    while (1){
        fib[tot+1]=fib[tot]+fib[tot-1];
        if (fib[tot+1]>inf) break;
        tot++;
    }
    a[1].pb(mp(1,2));a[1].pb(mp(1,3));a[1].pb(mp(1,4));
    fo(i,1,tot-3){
        it=a[i].begin();
        while (it!=a[i].end()){
            x=(*it).xx;y=(*it).yy;
            x+=y;
            while (x<=fib[i+3]+fib[i]){
                a[i+1].pb(mp(y,x));
                x+=y;
            }
            it++;
        }
    }
    scanf("%d",&ca);
    while (ca--){
        scanf("%lld%lld",&n,&m);
        if (n>m) swap(n,m);
        ans=1;
        while (fib[ans+1]<=n&&fib[ans+2]<=m) ans++;
        printf("%d ",ans);
        if (ans==1){
            printf("%lld\n",n*m%mo);
            continue;
        }
        else{
            num=0;
            it=a[ans-1].begin();
            while (it!=a[ans-1].end()){
                x=(*it).xx;y=(*it).yy;
                if (y<=n) (num+=(m-x)/y)%=mo;
                if (y<=m) (num+=(n-x)/y)%=mo;
                it++;
            }
            printf("%d\n",num);
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值