题目:Light oj 1070 - Algebraic Problem
思路:这题之前有做过类似的,方法还是构造矩阵,但是这个mod有点挫,mod=2^64 这个值不好取,如果直接做的话,mod=0这样就RuntimeError了
对于用long long 来表示的数字,大小是从-2^64~2^64-1 所以我的运算里如果全部不取模,那么到最后如果是一个正数就直接输出,如果是一个负数的话,相当于整个模是2^65,那么对于进到负数的部分,先乘以-1,然后用2^64减去这个正数得到的就是答案(这个过程我开了一个65位的数组进行模拟的),最后输出当然用unsigned long long 没办法,数据太挫了
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
struct Matrix
{
long long m[3][3];
}E,D;
int num[65];
int tum[65];
long long p,q;
void init()
{
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
E.m[i][j]=(i==j);
}
void make()
{
D.m[1][1]=p;
D.m[1][2]=-q;
D.m[2][1]=1;
D.m[2][2]=0;
}
Matrix Multi(Matrix A,Matrix B)
{
Matrix ans;
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
{
ans.m[i][j]=0;
for(int k=1;k<=2;k++)
{
ans.m[i][j]=(ans.m[i][j]+A.m[i][k]*B.m[k][j]);
}
}
return ans;
}
Matrix Pow(Matrix A,int k)
{
Matrix ans=E;
while(k)
{
if(k&1)
{
k--;
ans=Multi(ans,A);
}
else
{
k/=2;
A=Multi(A,A);
}
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
init();
for(int cases=1;cases<=t;cases++)
{
long long n;
scanf("%lld%lld%lld",&p,&q,&n);
make();
Matrix tmp;
tmp.m[1][1]=p;
tmp.m[2][1]=2;
printf("Case %d: ",cases);
if(n==0)
printf("%lld\n",2);
else
{
Matrix ans=Pow(D,n-1);
Matrix cnt;
for(int i=1;i<=2;i++)
{
cnt.m[i][1]=0;
for(int j=1;j<=2;j++)
cnt.m[i][1]=(cnt.m[i][1]+ans.m[i][j]*tmp.m[j][1]);
}
if(cnt.m[1][1]>0)
printf("%lld\n",cnt.m[1][1]);
else{
cnt.m[1][1]*=-1;
for(int i=0;i<=64;i++)
{
num[i]=0;
tum[i]=0;
}
num[64]=1;
int tnt=0;
while(cnt.m[1][1])
{
tum[tnt++]=cnt.m[1][1]%2;
cnt.m[1][1]/=2;
}
int carry=0;
for(int i=0;i<=64;i++)
{
num[i]-=tum[i]+carry;
if(num[i]<0)
{
num[i]+=2;
carry=1;
}
else
carry=0;
}
unsigned long long sy=0;
long long pp=1;
for(int i=0;i<=64;i++)
{
sy+=num[i]*pp;
pp*=2;
}
printf("%llu\n",sy);
}
}
}
return 0;
}