http://newoj.acmclub.cn/contests/1392/problem/1
题目描述:
终于活成了自己讨厌的样子。
听说多听电音能加快程序运行的速度。
定义一个数列,告诉你a\_0,a\_1,m\_0,m\_1,ca0,a1,m0,m1,c,定义a\_n=m\_0a\_{n-1}+m\_1a\_{n-2}+can=m0an−1+m1an−2+c对所有n\geq 2n≥2。
求\left( \prod\_{i=0}^{k}{a\_i} \right) mod M(∏i=0kai)modM
输入:
第一行一个整数T(1\leq T\leq 1000)T(1≤T≤1000),表示数据组数。
每组数据一行77个整数a\_0,a\_1,m\_0,m\_1,c,M,ka0,a1,m0,m1,c,M,k,保证1\leq M\leq 10^{18},0\leq a\_0,a\_1,m\_0,m\_1,c< M, 2\leq k\leq 10^61≤M≤1018,0≤a0,a1,m0,m1,c<M,2≤k≤106,保证MM为奇数。
保证\sum k \leq 10^8∑k≤108。
输出:
对于每组数据,输出一行表示答案。
样例输入
1
1 1 1 1 0 1000000007 10
样例输出
904493530
这一道题目看上去就是一道简单的连乘的题目,但是细心的话会发现数字是非常的大所以会有当被取的余数非常大的话就
会出现溢出的情况,所以我们在计算的时候要考虑到这一点情况,否则最后求出的数字肯定是不正确的;
处理方案一:这种方法可能会超时,补题的时候没有用,不知道会不会超时,它的一次乘法的时间复杂度是log()的,就是将
连乘的其中一个数字用二进制的数字来表示,这样的话就可以在计算的时候枚举用二进制表示的数字的每一位将乘法转化为加法并且可以边加边取模,这样的话就不会出现溢出的情况但是时间是很爆照的;
处理方案二: 这个处理的方法是很骚的就是可以用o(1)的时间复杂度将我们要的连乘给算出来并且可以防止溢出;
typedef ll ksc( ll a, ll b, ll mod ) //前面的两个数字分别是我们要用乘法来连乘得数字,后面的一个是我们要取模的数字;
{
return ( a*b - (ll) ( (long double ) a/mod*b) * mod+mod )%mod;
}
虽然我不知道这是什么原理但是这个样子的话是真的可以把题目给做出来;
#include <bits/stdc++.h>
using namespace std;
#define rep(i,s, n) for(int i=s;i<=n;i++)
#define per(i,n,s) for(int i=n;i>=s;i--)
const int Max = 2e6+10;
typedef long long ll;
ll a[Max],a0,a1,m0,m1,c,mod,k;
ll ksc(ll a, ll b, ll mod){
return (a*b-(ll)((long double )a/mod*b)*mod+mod)%mod;
}
int t;
int main(){
scanf("%d",&t);
while(t--) {
scanf("%lld %lld %lld %lld %lld %lld %lld",&a0,&a1,&m0,&m1,&c,&mod,&k);
m0%=mod;
m1%=mod;
a0%=mod;
a1%=mod;
c%=mod;
a[0]=a0;
a[1]=a1;
ll sum=ksc(a[0],a[1],mod);
ll ans1,ans2;
sum=(sum%mod+mod)%mod;
rep(i,2,k){
ans1=ksc(m0,a[i-1],mod);
ans2=ksc(m1,a[i-2],mod);
a[i]=ans1+ans2+c;
a[i]=(a[i]%mod+mod)%mod;
sum=ksc(sum,a[i],mod);
sum=(sum%mod+mod)%mod;
}
printf("%lld\n",(sum%mod+mod)%mod);
}
return 0;
}