P4910 帕秋莉的手环

 

题目背景

帕秋莉是蕾米莉亚很早结识的朋友,现在住在红魔馆地下的大图书馆里。不仅擅长许多魔法,还每天都会开发出新的魔法。只是身体比较弱,因为哮喘,会在咏唱符卡时遇到麻烦。

她所用的属性魔法,主要是生命和觉醒的“木”,变化和活动的“火”,基础和不动的“土”,果实和丰收的“金”,寂静和净化的“水”,机动和攻击的“日”,被动和防御的“月”七种属性

没有窗户的图书馆或许充满了灰尘,不过她认为在书旁边才是自己,所以她不能从书的旁边离开。这样已经一百年了。

题目描述

经过数年魔法的沉淀,帕秋莉将她那浩瀚无边的魔法的一部分浓缩到了一些特质的珠子中。

由于帕秋莉爱好和平,她只把象征生命和觉醒的木属性魔法和果实和丰收的金属性魔法放入了珠子中。

她认为光要这些珠子没有什么用处,于是她想将这些珠子串成魔法手环,这样就好看多了。于是,她拿出来用来串这些珠子的线 - 雾雨灵径。

她将这些珠子串到一起之后发现了一些性质:一段雾雨灵径的颜色是由两边的珠子的属性决定的,当一段雾雨灵径连接的两个珠子中只要有一个是金属性的,那么这段雾雨灵径的颜色就为金色

帕秋莉想要一个全都是金色的手环,而且她还想知道一共有多少种方案。由于她还要研究新的魔法,她就把这件事交给了你。由于她的魔法浩瀚无边,她有无穷的珠子

她并不想看着好几十位的数字,于是你需要对 1000000007 进行取模

输入输出格式

输入格式:

输入包含多组数据

第一行一个正整数 TTT ,表示数据组数。

之后每组数据有一个 nnn 代表木属性珠子和金属性珠子的总个数

输出格式:

对于每组数据,输出取模后的方案数

输入输出样例

输入样例#1: 
2
5
20
输出样例#1: 
11
15127
输入样例#2: 
3
9
99
999
输出样例#2: 
76
281781445
445494875
输入样例#3: 
5  
123
1234
12345
123456
1234567
输出样例#3: 
528790589
200102666
537707871
262341000
534036342

说明

这里给出 n=5 时,样例的解释

使用 1,2,3,4,5 来代表各个珠子

可行的方案是

{1,3,5},{1,2,4},{1,3,4},{2,3,5},{2,4,5}

{1,2,3,4},{1,2,3,5},{1,2,4,5},{1,3,4,5},{2,3,4,5}

{1,2,3,4,5}

对于 20% 的数据,有 1≤n≤10

对于 40% 的数据,有 1≤n≤102

对于 60% 的数据,有 1≤n≤106

对于 90% 的数据,有 1≤n≤109

对于全部的数据,有 1≤T≤10,1≤n≤1018

 

 

Solution:

  本题矩阵快速幂。

  直接打一张小一点的表,然后就能找出规律,得到递推关系:$f[1]=1,f[2]=3…f[i]=f[i-1]+f[i-2]$。

  不难发现这就是个类斐波那契数列,于是直接矩乘。

代码:

/*Code by 520 -- 10.8*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
#define clr(p) memset(&p,0,sizeof(p))
using namespace std;
const int mod=1e9+7;
struct matrix{
    int r,c;ll a[3][3];
};

il matrix mul(matrix x,matrix y){
    matrix tp; clr(tp);
    tp.r=x.r,tp.c=y.c;
    For(i,0,x.r-1) For(j,0,y.c-1) For(k,0,x.c-1)
    tp.a[i][j]=(tp.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
    return tp; 
}

int main(){
    int T;scanf("%d",&T);
    matrix ans,tp; clr(ans),clr(tp);
    ans.r=1,ans.c=2; tp.r=tp.c=2;
    while(T--){
        ll n;
        scanf("%lld",&n);
        ans.a[0][0]=2,ans.a[0][1]=1;
        tp.a[0][0]=0,tp.a[0][1]=tp.a[1][0]=tp.a[1][1]=1;
        while(n){
            if(n&1) ans=mul(ans,tp);
            n>>=1,tp=mul(tp,tp);
        }
        printf("%lld\n",ans.a[0][0]);
    }
    return 0;
}    

 

转载于:https://www.cnblogs.com/five20/p/9801209.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值