您的位置:首页 > 其它

【HDU 1005 && ZOJ 3539】简单矩阵dp

2012-12-10 12:53 489 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1005

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3538

1005题目大意:

告诉你f[1]=1, f[2]=1, f
=(A*f[n-1]+B*f[n-2])%7;然后输入A,B,n,让你求f


解题思路:

解法1:n比较大,给你这样递推式子一般不可能让你全部求出来,一般是有规律可寻的。只要在递推的过程中发现f[n-1]==f[1],f
==f[2],停止递推。把它多少个数循环一次记录下来,然后只需要用n对这个数取余即可。

解法2: 巧用矩阵dp 。 一般的矩阵dp是要你自己推出这个递推式,然后再构造矩阵。这题更简单一些,因为题目已经给好了你递推式,f[1],f[2]为特殊项,这里我们不考虑,把f[3]当做第一项来考虑。

f[3]=A+B, f[4]=A*(A+B)+B

这里递推式可以分解为两项,可以先把[A B](f[3]的两项)提出来,一般的矩阵dp为2阶,所以这样还是不够的。再观察递推式,求f[n+1]时我们还要用到前面两项,f
就在之前,所以我们还要把前面出现的f[n-1]保存下来,即让A对应的为1。这样就可以构造矩阵 | A B | 了。

| 1 0 |

View Code

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

#define mod 1000000007
typedef long long lld;

struct Node
{
int d;
char str[5];
bool operator<(const Node &S)const
{
return d<S.d;
}
}f[20];

struct Maxtri
{
lld mat[2][2];
};

Maxtri A, B;

void init()
{
A.mat[0][0]=1,A.mat[0][1]=0;
A.mat[1][0]=0,A.mat[1][1]=1;
B.mat[0][0]=0,B.mat[0][1]=1;
B.mat[1][0]=3,B.mat[1][1]=2;
}

lld Maxtri_mod(lld a, int b)
{
lld ans=1;
while(b)
{
if(b&1)
ans=(ans*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ans;
}

Maxtri Maxtri_mul(Maxtri a, Maxtri b)
{
Maxtri c;
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
{
c.mat[i][j]=0;
for(int k=0; k<2; k++)
c.mat[i][j]+=(a.mat[i][k]*b.mat[k][j])%mod;
c.mat[i][j]%=mod;
}

return c;
}

lld Maxtri_mi(int b, int p)
{
Maxtri ans=A, tp=B;
while(b)
{
if(b&1)
ans=Maxtri_mul(ans,tp);
b>>=1;
tp=Maxtri_mul(tp,tp);
}
if(p==0)
return ans.mat[1][0]%mod;
else
return  ans.mat[1][1]%mod;
}

int main()
{
int n, m;
init();
while(~scanf("%d%d",&n,&m))
{
if(m==0)
{
lld ans=Maxtri_mod(3,n-1)*4%mod;
printf("%lld\n",ans);
continue;
}
for(int i=0; i<m; i++)
scanf("%d %s",&f[i].d,f[i].str);
sort(f,f+m);
lld ans=Maxtri_mod(3,f[0].d-1)%mod;
for(int i=1; i<m; i++)
{
if(f[i].d-f[i-1].d-1==0) ///!!!
{
if(*f[i].str==*f[i-1].str)
{
cout << 0 <<endl; goto loop;  ///直接跳出循环到loop
}
else continue;
}
else
{
if(*f[i].str==*f[i-1].str) /// 开始忘记打*号比较值,不打则是比较地址
ans=ans*Maxtri_mi(f[i].d-f[i-1].d-1,0)%mod;
else
ans=ans*Maxtri_mi(f[i].d-f[i-1].d-1,1)%mod;
}
}
ans=ans*Maxtri_mod(3,n-f[m-1].d)%mod;
printf("%lld\n",ans);
loop:{}
}
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: