[Luogu] P4910 帕秋莉的手环
题目背景
帕秋莉是蕾米莉亚很早结识的朋友,现在住在红魔馆地下的大图书馆里。不仅擅长许多魔法,还每天都会开发出新的魔法。只是身体比较弱,因为哮喘,会在咏唱符卡时遇到麻烦。
她所用的属性魔法,主要是生命和觉醒的“木”,变化和活动的“火”,基础和不动的“土”,果实和丰收的“金”,寂静和净化的“水”,机动和攻击的“日”,被动和防御的“月”七种属性
没有窗户的图书馆或许充满了灰尘,不过她认为在书旁边才是自己,所以她不能从书的旁边离开。这样已经一百年了。
题目描述
经过数年魔法的沉淀,帕秋莉将她那浩瀚无边的魔法的一部分浓缩到了一些特质的珠子中。
由于帕秋莉爱好和平,她只把象征生命和觉醒的木属性魔法和果实和丰收的金属性魔法放入了珠子中。
她认为光要这些珠子没有什么用处,于是她想将这些珠子串成魔法手环,这样就好看多了。于是,她拿出来用来串这些珠子的线 - 雾雨灵径。
她将这些珠子串到一起之后发现了一些性质:一段雾雨灵径的颜色是由两边的珠子的属性决定的,当一段雾雨灵径连接的两个珠子中只要有一个是金属性的,那么这段雾雨灵径的颜色就为金色
帕秋莉想要一个全都是金色的手环,而且她还想知道一共有多少种方案。由于她还要研究新的魔法,她就把这件事交给了你。由于她的魔法浩瀚无边,她有无穷的珠子
她并不想看着好几十位的数字,于是你需要对1000000007进行取模
题目解析
一眼不可做系列
首先理解一下题,一段线是金色的仅当它的两个端点至少有一个金属球。
然后…
没有高大上算法,只有手玩小数据得到的规律:
n |
答案 |
1 | 1 |
2 | 3 |
3 | 4 |
4 | 7 |
5 | 10 |
规律就是ans[i] = ans[1-1] + ans[i-2]
鉴于数据范围矩阵乘法
Code
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const long long MAXN = 1e18; const long long p = 1000000007; struct Matrix { long long m[4][4]; int sx,sy; } str,pro; long long n; inline void init() { str.m[1][1] = 1; str.m[1][2] = 3; str.sx = 1, str.sy = 2; pro.m[1][1] = 0; pro.m[1][2] = pro.m[2][1] = pro.m[2][2] = 1; pro.sx = pro.sy = 2; return; } inline Matrix mul(Matrix x,Matrix y) { Matrix res; memset(res.m,0,sizeof(res.m)); res.sx = x.sx, res.sy = y.sy; for(register int i = 1;i <= x.sx;i++) { for(register int j = 1;j <= y.sy;j++) { for(register int k = 1;k <= x.sy;k++) { res.m[i][j] += x.m[i][k] * y.m[k][j] % p; res.m[i][j] %= p; } } } return res; } inline Matrix quick_pow(Matrix x,long long y) { Matrix res; res.sx = x.sx, res.sy = x.sy; for(register int i = 1;i <= res.sx;i++) { for(register int j = 1;j <= res.sy;j++) { if(i == j) res.m[i][j] = 1; else res.m[i][j] = 0; } } while(y) { if(y & 1) res = mul(res,x); x = mul(x,x); y >>= 1; } return res; } int main() { int T; scanf("%d",&T); init(); str = mul(str,pro); while(T--) { scanf("%lld",&n); init(); Matrix ans = mul(str,quick_pow(pro,n-1)); printf("%lld\n",ans.m[1][1] % p); } return 0; }
所有博文均为原创 转载请留言征得博主同意