原题: https://ac.nowcoder.com/acm/contest/885/B
题意:
给出 x 0 , x 1 , a , b x_0,x_1,a,b x0,x1,a,b, x i = a x i − 1 + b x i − 2 x_i=ax_{i-1}+bx_{i-2} xi=axi−1+bxi−2,现在给出 n ∈ [ 1 , 1 0 1 0 1 e 6 ] n\in[1,10^{10^{1e6}}] n∈[1,10101e6],求 x n x_n xn
解析:
以为java的BigInteger转成二进制(.toString(2)
)很快,没想到TLE了。可以参考参考
import java.math.*;
import java.util.*;
public class Main {
public static BigInteger Two=BigInteger.valueOf(2);
public static BigInteger One=BigInteger.valueOf(1);
public static BigInteger Zero=BigInteger.valueOf(0);
public static BigInteger Ten=BigInteger.valueOf(10);
public static long mod;
public static long res[][]=new long[2][];
public static long A[][]=new long[2][];
public static long bas[][]=new long[2][];
public static long tmp[][]=new long[2][];
public static void mul_res() {
tmp[0][0]=tmp[0][1]=tmp[1][0]=tmp[1][1]=0;
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
for(int k=0;k<2;k++) {
tmp[i][j]+=res[i][k]*A[k][j];
tmp[i][j]%=mod;
}
}
}
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
res[i][j]=tmp[i][j];
}
}
}
public static void mul_A() {
tmp[0][0]=tmp[0][1]=tmp[1][0]=tmp[1][1]=0;
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
for(int k=0;k<2;k++) {
tmp[i][j]+=A[i][k]*A[k][j];
tmp[i][j]%=mod;
}
}
}
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
A[i][j]=tmp[i][j];
}
}
}
public static void mul_bas_res() {
tmp[0][0]=tmp[0][1]=tmp[1][0]=tmp[1][1]=0;
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
for(int k=0;k<2;k++) {
tmp[i][j]+=bas[i][k]*res[k][j];
tmp[i][j]%=mod;
}
}
}
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
bas[i][j]=tmp[i][j];
}
}
}
public static void main(String args[]) {
Scanner cin=new Scanner(System.in);
long x0,x1,a,b;
x0=cin.nextInt();
x1=cin.nextInt();
a=cin.nextInt();
b=cin.nextInt();
BigInteger n;n=cin.nextBigInteger();
mod=cin.nextInt();
String bit=n.toString(2);
int len=bit.length();
// System.out.println(bit);
res[0]=new long[2];
res[1]=new long[2];
A[0]=new long[2];
A[1]=new long[2];
bas[0]=new long[2];
bas[1]=new long[2];
tmp[0]=new long[2];
tmp[1]=new long[2];
res[0][0]=res[1][1]=1;
res[0][1]=res[1][0]=0;
bas[0][0]=x1;bas[0][1]=x0;
bas[1][0]=bas[1][1]=0;
A[0][0]=a;A[0][1]=1;
A[1][0]=b;A[1][1]=0;
for(int i=len-1;i>=0;i--) {
if(bit.charAt(i)=='1') {
mul_res();
}
mul_A();
}
mul_bas_res();
System.out.println(bas[0][1]);
}
}
后来想到预处理出每个 1 0 k 10^k 10k次的结果,预处理到 1 0 1 0 1 e 6 10^{10^{1e6}} 10101e6。又或者可以再优化一下,每 1 e 8 1e8 1e8作为一个单位,那么直接按照十进制拆开就行。
代码:
#include
#include
#include
#define LL long long
#define N 2
using namespace std;
LL MOD;
const int maxn=1e6+5;
struct matrix{
int size;
LL mat[N][N];
matrix(int s=2){
size=s;for(int i=0;i<s;i++)for(int j=0;j<s;j++)mat[i][j]=0;
}
matrix operator * (const matrix & x)const{
matrix ans(x.size);
for(int i=0;i<x.size;i++){
for(int j=0;j<x.size;j++){
for(int k=0;k<x.size;k++){
ans.mat[i][j]=(ans.mat[i][j]+mat[i][k]*x.mat[k][j])%MOD;
}
}
}return ans;
}
} ;
matrix swift(matrix a,LL t){
matrix ans(a.size);
for(int i=0;i<a.size;i++)ans.mat[i][i]=1;
while(t){
if(t&1ll)ans=ans*a;
a=a*a;t>>=1;
}return ans;
}
char x[maxn];
matrix mul[maxn];
int main(){
int x0,x1,a,b;scanf("%d%d%d%d",&x0,&x1,&a,&b);
scanf("%s",x);
int len=strlen(x);
scanf("%lld",&MOD);
matrix bas;
bas.mat[0][0]=x1,
bas.mat[0][1]=x0,
mul[0].mat[0][0]=a,
mul[0].mat[1][0]=b,
mul[0].mat[0][1]=1;
const int LEN=8;
for(int i=LEN;i<=1e6+1;i+=LEN){
mul[i]=swift(mul[i-LEN],100000000ll);
}
matrix ans;
for(int i=0;i<2;i++)ans.mat[i][i]=1;
for(int i=len-1;i>=0;i-=LEN){
int num=0;
for(int j=0,k=1;j<LEN;j++,k*=10){
if(i-j<0)break;
num+=(x[i-j]-'0')*k;
}
if(num==0)continue;
ans=ans*swift(mul[len-1-i],num);
}
bas=bas*ans;
printf("%lld\n",bas.mat[0][1]);
}