【loj6257】「CodePlus 2017 12 月赛」可做题2

题目描述
“codeplus比赛的时候在做什么?有没有空?能来解决丢番图方程问题吗?”sublinekelzrip这样问qmqmqm。

当然,qmqmqm并不会丢番图方程问题,所以sublinekelzrip改为提出了另一个题目,现在请你帮助qmqmqm解决这个题目。

这个问题是这样的:

若一个数列aaa满足条件an=an−1+an−2,n≥3a_n=a_{n-1}+a_{n-2},n \geq 3a
​n
​​ =a
​n−1
​​ +a
​n−2
​​ ,n≥3,而a1,a2a_1,a_2a
​1
​​ ,a
​2
​​ 为任意实数,则我们称这个数列为广义斐波那契数列。

现在请你求出满足条件a1=ia_1=ia
​1
​​ =i,a2a_2a
​2
​​ 为区间[l,r][l,r][l,r]中的整数,且
a
k
mod

p

m
的广义斐波那契数列有多少个。
输入格式
从标准输入读入数据。

本题包含多组数据,输入第一行包含一个正整数TTT,表示数据组数。对于每组数据:

一行六个用空格隔开的整数i,l,r,k,p,mi,l,r,k,p,mi,l,r,k,p,m,意义如「题目描述」所示。
输出格式
输出到标准输出。

输出共TTT行,每行一个数表示该组数据的答案。
样例
样例输入

6
2 17 68 3 23 1
1 17 68 3 57 1
5 17 68 10 11 9
5 17 68 10 71 9
10 17 68 11 12 3
10 17 68 8 6 4
样例输出

3
1
4
1
5
9
数据范围与提示
测试点 kkk rrr 其他
1 ≤100\leq 100≤100 ≤100\leq 100≤100 无
2 ≤105\leq 10^5≤10
​5
​​ ≤105\leq 10^5≤10
​5
​​
3
4 ≤1018\leq 10^{18}≤10
​18
​​
5
6 ≤105\leq 10^5≤10
​5
​​ ≤1018\leq 10^{18}≤10
​18
​​ ppp为质数
7
8 ≤ 1018\leq 10^{18}≤10
​18
​​
9 无
10
对于所有数据,0≤l≤r0 \leq l \leq r0≤l≤r,1≤p≤1091 \leq p \leq 10^91≤p≤10
​9
​​ ,0≤m< p0 \leq m < p0≤m< p,T=10T=10T=10,0≤i≤10180 \leq i \leq 10^{18}0≤i≤10
​18
​​ ,k≥3k \geq 3k≥3。

来自 CodePlus 2017 12 月赛,清华大学计算机科学与技术系学生算法与竞赛协会 荣誉出品。
Credit:idea/卢政荣 命题/卢政荣 验题/吕时清,茹逸中,王聿中
Git Repo:https://git.thusaac.org/publish/CodePlus201712
感谢腾讯公司对此次比赛的支持。

题解
第k项(ai+bx,l<=x<=r)的系数a,b,是斐波那契数列中的两项,可以通过矩阵求得。
然后就是解同余方程。

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 1000000000
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll a[3][3],b[3][3];
ll x,l,r,k,p,m,y;
void mul(ll a[3][3],ll b[3][3],ll c[3][3])
{
    ll tmp[3][3];
    for (int i=1;i<=2;i++)
        for (int j=1;j<=2;j++)
        {
            tmp[i][j]=0;
            for (int k=1;k<=2;k++)
                (tmp[i][j]+=a[i][k]*b[k][j]%p)%=p;
        }
    for (int i=1;i<=2;i++)
        for (int j=1;j<=2;j++)
            c[i][j]=tmp[i][j];
}
ll get(ll k)
{
    if (k==-2) return 1;
    if (k==-1) return 0;
    if (k==0) return 1;
    b[1][1]=b[2][2]=1;b[1][2]=b[2][1]=0;
    a[1][1]=1;a[1][2]=1;a[2][1]=1;a[2][2]=0;
    while (k)
    {
        if (k&1) mul(a,b,b);
        mul(a,a,a);
        k>>=1;
    }
    return b[1][1];
}
ll exgcd(ll a,ll b)
{
    if (b==0){x=1;y=0;return a;}
    ll d=exgcd(b,a%b);
    ll t=x;
    x=y;y=t-a/b*y;
    return d; 
}
void solve()
{
    scanf("%lld%lld%lld%lld%lld%lld",&x,&l,&r,&k,&p,&m);x%=p;
    ll i=get(k-3),A=get(k-2);
    i=i*x%p;i=((m-i)%p+p)%p;
    ll d=exgcd(A,p);
    if (i%d){puts("0");return;}
    x=x*i/d;ll q=p/d;
    x=x+(l-x)/q*q;
    if (x<l) x+=q;
    if (x>r) puts("0");else printf("%lld\n",(r-x)/q+1);
}
int main()
{
    int Case=read();
    while (Case--) solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值