可做题2(Code+12月网络赛)(扩欧+矩阵快速幂)
来源:互联网 发布:ubuntu软件库打不开 编辑:程序博客网 时间:2024/06/07 07:14
题目背景
“codeplus比赛的时候在做什么?有没有空?能来解决丢番图方程问题吗?”sublinekelzrip这样问qmqmqm。
当然,qmqmqm并不会丢番图方程问题,所以sublinekelzrip改为提出了另一个题目,现在请你帮助qmqmqm解决这个题目。
题目描述
这个问题是这样的:
若一个数列
现在请你求出满足条件
输入格式
从标准输入读入数据。
本题包含多组数据,输入第一行包含一个正整数
一行六个用空格隔开的整数题目描述
所示。
输出格式
输出到标准输出。
输出共
样例1输入
62 17 68 3 23 11 17 68 3 57 15 17 68 10 11 95 17 68 10 71 910 17 68 11 12 310 17 68 8 6 4
样例1输出
314159
子任务
对于所有数据,
题解:
算法一
暴力枚举所有可能的
复杂度
算法二
使用递推计算出系数,并暴力枚举所有可能的
复杂度
算法三
暴力枚举所有可能的
复杂度
算法四
与算法二类似,使用递推计算出系数,此时可以发现可能的
可以通过测试点6,7。
算法五
将算法四中计算系数的方式改为矩阵乘法,可以通过测试点8。
算法六
由于
考场上果断算法三
后来虚泽口hu出了正解
如果知道了首项和第二项
我们就可以用矩阵快速幂求出第k项
相当于我们已知a[k]%p,a[1],fib(k-2),fib(k-1),
令a=fib(k-1),b=m-i*fib(k-2),x=a[2],
则方程转化为:a*x ≡ b(%p),求解x=[l,r]的整数解
运用exgcd求解过程:
- 转化为不定方程:ax-py=b
- g=gcd(a,p),若b%p≠0则无解(输出0)
- a/=g,p/=g,b/=g
- 求解a’x-p’y=1即exgcd(a,p)
- 得到最小非负整数解x=x*b(如果x<0,我们需要通过+p%p处理一下)
- 计算在[l,r]之间的解:cal(r,x)-cal(l-1,x)
ll cal(ll r,ll x){ if (r<x) return 0; return (r-x)/p+1; //每隔p个就有一解}
tip
i读入的时候就需要%p
在solve的时候:p —> p/gcd(a,p)
不知道这是什么鬼畜原理,
可能是因为求解是建立在:ax+py=gcd(a,p) 的基础上
之后的解也是每隔p/gcd(a,p)就有一个
//这里写代码片#include<cstdio>#include<cstring>#include<iostream>#define ll long longusing namespace std;ll p;struct node{ ll H[3][3]; node operator *(const node &a) const { node ans; for (int i=1;i<=2;i++) for (int j=1;j<=2;j++){ ans.H[i][j]=0; for (int k=1;k<=2;k++) ans.H[i][j]=(ans.H[i][j]+H[i][k]*a.H[k][j])%p; } return ans; } void clear() { memset(H,0,sizeof(H)); } node KSM(ll p) { node ans=(* this); node a=(* this); p--; while (p) { if (p&1) ans=ans*a; p>>=1; a=a*a; } return ans; }};node H;ll i,l,r,k,m,x,y;ll gcd(ll a,ll b){ ll r=a%b; while (r) { a=b; b=r; r=a%b; } return b;}void exgcd(ll a,ll b){ if (b==0) { x=1; y=0; return; } exgcd(b,a%b); ll t=x; x=y; y=t-a/b*y;}ll cal(ll r,ll x){ if (r<x) return 0; return (r-x)/p+1;}ll solve(ll a,ll b){ ll c=gcd(a,p); if (b%c!=0) return 0; a/=c; b/=c; p/=c; //p/=c exgcd(a,p); x=(x*b+p)%p; //解 while (x<0) x=(x+p)%p; return (ll)(cal(r,x)-cal(l-1,x));}int main(){ H.H[1][1]=1; H.H[1][2]=1; H.H[2][1]=1; H.H[2][2]=0; int T; scanf("%d",&T); while (T--) { scanf("%lld%lld%lld%lld%lld%lld",&i,&l,&r,&k,&p,&m); i%=p; node ans=H.KSM(k-2); ll f1=ans.H[1][1]%p; //fib(k-1) ll f2=((m-ans.H[2][1]%p*i%p)%p+p)%p; //fib(k-2) //f1*x ≡f2(%p) printf("%lld\n",solve(f1,f2)); } return 0;}