Numbers(2008 Round 1A C)矩阵快速幂

来自《挑战程序设计竞赛》

1.题目原文

Problem

In this problem, you have to find the last three digits before the decimal point for the number (3 + √5)n.

For example, when n = 5, (3 + √5)5 = 3935.73982... The answer is 935.

For n = 2, (3 + √5)2 = 27.4164079... The answer is 027.

Input

The first line of input gives the number of cases, TT test cases follow, each on a separate line. Each test case contains one positive integer n.

Output

For each input case, you should output:

Case #X: Y
where  X  is the number of the test case and  Y  is the last three integer digits of the number (3 + √5) n . In case that number has fewer than three integer digits, add leading zeros so that your output contains exactly three digits.

Limits

1 <= T <= 100

Small dataset

2 <= n <= 30

Large dataset

2 <= n <= 2000000000

Sample


Input 
 

Output 
 
2
5
2
Case #1: 935
Case #2: 027

2.解题思路

裸的矩阵快速幂。

3.AC代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<utility>
#include<queue>
using namespace std;

typedef vector<int> vec;
typedef vector<vec> mat;
typedef long long ll;
const int M=10000;
//计算A*B
mat mul(mat& A,mat& B)
{
    mat C(A.size(),vec(B[0].size()));
    for(int i=0;i<A.size();i++){
        for(int k=0;k<C.size();k++){
            for(int j=0;j<B.size();j++){
                C[i][j]=(C[i][j]+A[i][k]*B[k][j])%M;
            }
        }
    }
    return C;
}
//计算A^n
mat pow(mat A,ll n)
{
    mat B(A.size(),vec(A.size()));
    for(int i=0;i<A.size();i++){
        B[i][i]=1;
    }
    while(n>0){
        if(n&1) B=mul(B,A);
        A=mul(A,A);
        n>>=1;
    }
    return B;
}

const int Mod=1000;

int n;
void solve()
{
    mat A(2,vec(2,0));
    A[0][0]=3;A[0][1]=5;
    A[1][0]=1;A[1][1]=3;
    A=pow(A,n);
    printf("%03d\n",(A[0][0]*2+Mod-1)%Mod);
}
int main()
{
    //注意GCJ需要提交输出文件,正式比赛还需要提交源代码
    freopen("C-large-practice.in","r",stdin);
    freopen("C-large-practice.out","w",stdout);
    int t,kase=0;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        printf("Case #%d: ",++kase);
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值