题目链接:http://47.93.249.116/problem.php?id=2182

题目描述

河神喜欢吃零食,有三种最喜欢的零食,鱼干,猪肉脯,巧克力。他每小时会选择一种吃一包。

不幸的是,医生告诉他,他吃这些零食的时候,如果在连续的三小时内他三种都吃了,并且在中间一小时

吃的是巧克力,他就会食物中毒。并且,如果河神在连续三小时内吃到相同种类的食物,他就会不开心。

假设每种类零食的数量都是无限的,那么如果经过n小时,让河神满意的零食吃法有多少种呢?(开心又不

会食物中毒的吃法)答案可能过大,结果对1000000007取模。

输入

第一行一个T,代表测试实例数(T<=1000)

第二行一个n,代表经过n个小时。(n<=1e10)

输出

每行一个结果,代表经过n小时河神满意的零食吃法的数量。

样例输入

3
3
4
15

样例输出

22
54
1034422 一道比较水的矩阵题,但因出题人语文素养过低,签到阅读题表意不清导致全场没时间开这题,emmm。。。。 官方题解+AC代码:
/*

从数据量上可以很明显的看出,1e10必定不是暴力直接递推。联想到矩阵快速幂

 

可以很明显的看出,前两项是不受规则影响的,所以前两项直接输出。

 

从第三项开始是满足规则的状态转移(dp),因为从第三项开始才满足规则,

 

因此第三项相当于dp序列的第一项,用快速幂计算时需要减去2.

 

解决dp问题的关键在于能否把大问题分解为较小数量级的子问题,即可以子问题

 

作为已知条件推出更多答案。

 

对于初始规则矩阵的构造,假设我们用0,1,2分别表示三种零食,其中1代表

 

巧克力,那么对于规则来说,第n小时的可选择零食只需看之前两个小时的

 

选择(因为只需要判断连续三小时内是不是合法),为了方便书写,在代码

 

中采用状态压缩的方法表示,那么代表每个小时选择的有三种,即压缩为三

 

进制数即可。比如,21=(2*3^1+1*3^0=5)代表前两小时分别吃了鱼干和

 

巧克力。那么对于当前状态5可达成的状态,只有11,12,因为规则中210是会

 

食物中毒的(我们保留了后两位但在保留过程中以三位判断是否是合法的状态

 

转移)。dp[n][k] = Σdp[n-1][u](所有合法的可以转移到k的u),矩阵幂完美

 

实现任意状态的转移结果,最后把所有转移状态累加即得到答案。

*/

#include<stdio.h>

#include<string.h>

#include<algorithm>

#include<queue>

using namespace std;
const int MAXN = 9;
const long long mod=1e9+7;
struct Matrix
{
long long edge[MAXN][MAXN];
};
int N;
void Mul(Matrix a, Matrix b, Matrix &ans)
{
memset(ans.edge,0,sizeof(ans.edge));
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
for(int p=0; p<N; p++)
{
ans.edge[i][j] += (a.edge[i][p] * b.edge[p][j])%mod;
ans.edge[i][j]%=mod;
} } void QuickPow(Matrix Map, long long k, Matrix &ans) {
memset(ans.edge,0,sizeof(ans.edge));
for(int i=0; i<N; i++)ans.edge[i][i] = true;
while(k)
{
if(k & 1)
Mul(ans, Map, ans);
Mul(Map, Map, Map);
k /= 2;
}
}
bool check(int i, int j)
{
int a = i%3, b = i/3%3;
int c = j%3, d = j/3%3;
if(a == b && b == c)
return false;
if(a!=d)
return false;
if(a==1 && b!=1 && c!=1 && b!=c)
return false;
return true;
}
int main()
{
//freopen("qq.txt","r",stdin);
// freopen("pp.txt","w",stdout);
int T; long long n;
scanf("%d", &T);
N = 9;
while(T--)
{ scanf("%lld", &n);
Matrix ans;
memset(ans.edge, 0, sizeof(ans.edge));
for(int i=0; i<9; i++)
{
for(int j=0; j<9; j++)
{
if(check(i, j))
ans.edge[i][j] = 1;
}
}
if(n<=2)
{
if(n == 1)
printf("3\n");
else printf("9\n");
}
else
{
QuickPow(ans, n-2, ans);
long long p = 0;
for(int i=0; i<9; i++)
for(int j=0; j<9; j++)
{
p = p+ans.edge[i][j];
p %= mod;
}
printf("%lld\n", p);
}
}
return 0;
}

其实直接手推前几项,然后杜教BM板子一套,加个杜教读入挂,恐怖如斯

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
//head
namespace IO{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
#define ll long long
// fread->read bool IOerror=0;
inline char nc(){
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if (p1==pend){
p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
if (pend==p1){IOerror=1;return -1;}
{printf("IO error!\n");system("pause");for (;;);exit(0);}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
inline void read(int &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(ll &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(double &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (ch=='.'){
double tmp=1; ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
}
if (sign)x=-x;
}
inline void read(char *s){
char ch=nc();
for (;blank(ch);ch=nc());
if (IOerror)return;
for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
*s=0;
}
inline void read(char &c){
for (c=nc();blank(c);c=nc());
if (IOerror){c=-1;return;}
}
// fwrite->write
struct Ostream_fwrite{
char *buf,*p1,*pend;
Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
void out(char ch){
if (p1==pend){
fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
}
*p1++=ch;
}
void print(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(double x,int y){
static ll mul[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,
1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL,
100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL};
if (x<-1e-12)out('-'),x=-x;x*=mul[y];
ll x1=(ll)floor(x); if (x-floor(x)>=0.5)++x1;
ll x2=x1/mul[y],x3=x1-x2*mul[y]; print(x2);
if (y>0){out('.'); for (size_t i=1;i<y&&x3*mul[i]<mul[y];out('0'),++i); print(x3);}
}
void println(double x,int y){print(x,y);out('\n');}
void print(char *s){while (*s)out(*s++);}
void println(char *s){while (*s)out(*s++);out('\n');}
void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
~Ostream_fwrite(){flush();}
}Ostream;
inline void print(int x){Ostream.print(x);}
inline void println(int x){Ostream.println(x);}
inline void print(char x){Ostream.out(x);}
inline void println(char x){Ostream.out(x);Ostream.out('\n');}
inline void print(ll x){Ostream.print(x);}
inline void println(ll x){Ostream.println(x);}
inline void print(double x,int y){Ostream.print(x,y);}
inline void println(double x,int y){Ostream.println(x,y);}
inline void print(char *s){Ostream.print(s);}
inline void println(char *s){Ostream.println(s);}
inline void println(){Ostream.out('\n');}
inline void flush(){Ostream.flush();}
#undef ll
#undef OUT_SIZE
#undef BUF_SIZE
}; int _;
long long n;
namespace linear_seq {
const int N=10010;
ll res[N],base[N],_c[N],_md[N]; vector<int> Md;
void mul(ll *a,ll *b,int k) {
rep(i,0,k+k) _c[i]=0;
rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
for (int i=k+k-1;i>=k;i--) if (_c[i])
rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
rep(i,0,k) a[i]=_c[i];
}
int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
printf("%d\n",SZ(b));
ll ans=0,pnt=0;
int k=SZ(a);
assert(SZ(a)==SZ(b));
rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
Md.clear();
rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
rep(i,0,k) res[i]=base[i]=0;
res[0]=1;
while ((1ll<<pnt)<=n) pnt++;
for (int p=pnt;p>=0;p--) {
mul(res,res,k);
if ((n>>p)&1) {
for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
}
}
rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
if (ans<0) ans+=mod;
return ans;
}
VI BM(VI s) {
VI C(1,1),B(1,1);
int L=0,m=1,b=1;
rep(n,0,SZ(s)) {
ll d=0;
rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
if (d==0) ++m;
else if (2*L<=n) {
VI T=C;
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
L=n+1-L; B=T; b=d; m=1;
} else {
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
++m;
}
}
return C;
}
int gao(VI a,ll n) {
VI c=BM(a);
c.erase(c.begin());
rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
}
}; int main() {
//freopen("int.txt","r",stdin);
// freopen("out.txt","w",stdout);
int t;
IO::read(t);
while(t--){
IO::read(n);
if(n==1) {IO::println("3");continue;}
else if(n==2) {IO::println("9");continue;} vector<int>v;
v.push_back(3);//前几项
v.push_back(9);
v.push_back(22);
v.push_back(54);
v.push_back(132);
v.push_back(324);
v.push_back(794);
v.push_back(1946);
v.push_back(4770);
v.push_back(11692);
v.push_back(28658);
v.push_back(70244);
v.push_back(172176);
v.push_back(422022); //输入n ,输出第n项的值
IO::println(linear_seq::gao(v,n-1));
printf("%d\n",linear_seq::gao(v,n-1));
}
}
// 3 9 22 54 132 324 794 1946 4770 11692 28658 70244 172176 422022 1034422
												

ZZNU 2182 矩阵dp (矩阵快速幂+递推式 || 杜教BM)的更多相关文章

  1. POJ3233:Matrix Power Series(矩阵快速幂+递推式)

    传送门 题意 给出n,m,k,求 \[\sum_{i=1}^kA^i\] A是矩阵 分析 我们首先会想到等比公式,然后得到这样一个式子: \[\frac{A^{k+1}-E}{A-E}\] 发现要用矩 ...

  2. hdu 5171(矩阵快速幂,递推)

    GTY's birthday gift Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe ...

  3. HDU2604:Queuing(矩阵快速幂+递推)

    传送门 题意 长为len的字符串只由'f','m'构成,有2^len种情况,问在其中不包含'fmf','fff'的字符串有多少个,此处将队列换成字符串 分析 矩阵快速幂写的比较崩,手生了,多练! 用f ...

  4. HDU 1757 矩阵求第n的递推式

    A Simple Math Problem Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  5. HDU - 2604 Queuing(递推式+矩阵快速幂)

    Queuing Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  6. POJ 3734 Blocks(矩阵快速幂+矩阵递推式)

    题意:个n个方块涂色, 只能涂红黄蓝绿四种颜色,求最终红色和绿色都为偶数的方案数. 该题我们可以想到一个递推式 .   设a[i]表示到第i个方块为止红绿是偶数的方案数, b[i]为红绿恰有一个是偶数 ...

  7. [题解][SHOI2013]超级跳马 动态规划/递推式/矩阵快速幂优化

    这道题... 让我见识了纪中的强大 这道题是来纪中第二天(7.2)做的,这么晚写题解是因为 我去学矩阵乘法啦啦啦啦啦对矩阵乘法一窍不通的童鞋戳链接啦 层层递推会TLE,正解矩阵快速幂 首先题意就是给你 ...

  8. 矩阵乘法&矩阵快速幂&矩阵快速幂解决线性递推式

    矩阵乘法,顾名思义矩阵与矩阵相乘, 两矩阵可相乘的前提:第一个矩阵的行与第二个矩阵的列相等 相乘原则: a b     *     A B   =   a*A+b*C  a*c+b*D c d     ...

  9. Luogu T7152 细胞(递推,矩阵乘法,快速幂)

    Luogu T7152 细胞(递推,矩阵乘法,快速幂) Description 小 X 在上完生物课后对细胞的分裂产生了浓厚的兴趣.于是他决定做实验并 观察细胞分裂的规律. 他选取了一种特别的细胞,每 ...

随机推荐

  1. mysql创建索引以及对索引的理解

    创建表的时候创建索引   创建索引是指在某个表的一列或多列上建立一个索引,以便提高对表的访问速度.创建索引有3种方式,这3种方式分别是创建表的时候创建索引.在已经存在的表上创建索引和使用ALTER T ...

  2. python学习Day4 流程控制(if分支,while循环,for循环)

    复习 1.变量名命名规范 -- 1.只能由数字.字母 及 _ 组成 -- 2.不能以数字开头 -- 3.不能与系统关键字重名 -- 4._开头有特殊含义 -- 5.__开头__结尾的变量,魔法变量 - ...

  3. 二十一、proxyDesign 代理模式

    原理: 时序图: 代码清单: Printable public interface Printable { void setPrinterName(String name); String getPr ...

  4. 使用 Ansible 统计服务器资源利用率

    使用 Ansible 统计服务器资源利用率: 3 条 shell 脚本实现统计: CPU 利用率统计: top -bn1 | grep load | awk '{printf "CPU Lo ...

  5. CentOS7 firewalld防火墙配置

    [root@ecs ~]# firewall-cmd --version       //查看版本0.3.9 [root@ecs ~]# firewall-cmd --state        //查 ...

  6. Centos7 进入单用户模式,修复系统

    一.开机时进入如下界面,(按下方向键盘,阻止系统自动继续) 按e键出现下面界面 按方向键下,定位到最后,找到“ro”一行,ro的意思是read only,将“ro”替换成 rw init=/sysro ...

  7. Volatile 关键字 内存可见性

    1.问题引入 实现线程: public class ThreadDemo implements Runnable { private boolean flag = false; @Override p ...

  8. centos平台基于snort、barnyard2以及base的IDS(入侵检测系统)的搭建与测试及所遇问题汇总

    centos平台基于snort.barnyard2以及base的IDS(入侵检测系统)的搭建与测试及所遇问题汇总 原创 2016年12月19日 01:20:03 标签: centos / snort  ...

  9. ping内网一台虚拟机延时很大(hyper-v虚拟机)的解决办法

    问题现象: ping 内网一台虚拟机延时很大,不稳定,造成业务系统响应慢.查看服务器上各种资源都正常. 解决办法: 在物理机上找到和hyper-v绑定的那个网卡,把“虚拟机队列”禁用掉就好了,如下图: ...

  10. downLoad

    String root= ServletActionContext.getServletContext().getRealPath(File.separator).replace("\\&q ...