您的位置:首页 > 其它

HDU 4471 矩阵快速幂 Homework

2013-09-02 12:40 232 查看
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4471
解题思路,矩阵快速幂····特殊点特殊处理·····

令h为计算某个数最多须知前h个数,于是写出方程:

D =

c1c2```c[h-1]c[h]
10```00
01```00
0000
0010
V[x] =

f[x]
f[x-1]
`
`
f[x-h+1]
显然有V[x+1] = D*V[x].D是由系数行向量,一个(h-1)*(h-1)的单位矩阵,和一个(h-1)*1的0矩阵组成。V[x]是一个h行,1列的矩阵。

初始条件为V[m] = (f[m],f[m-1],`````).如果m>h,那么多余的部分不会用到,如果m<h剩下的部分用0取代,相当于人为的添加前项f[0] = 0,f[-1] = 0·····这不会影响结果,而且式子仍然成立。由此计算出V
,答案就为V[1][1].

其余看一下代码就OK了,还有别人的解题报告,也可以看一下:

链接:
http://www.07net01.com/program/547544.html
我的代码:

#include<cstdio>
#include<algorithm>
using namespace std;
const int N =102;
const int mod = 1000000007;
int h;//计算f[x]时最多和前面h个数有关
struct matrix
{
int row,col;
int m

;
void init(int row,int col)
{
this->row = row;
this->col = col;
for(int i=0; i<=row; ++i)
for(int j=0; j<=col; ++j)
m[i][j] = 0;
}
} A,pm[33],ans;

matrix operator*(const matrix & a,const matrix& b)
{
matrix res;
res.init(a.row,b.col);
for(int k=1; k<=a.col; ++k)
{
for(int i=1; i<= res.row; ++i)
{
if(a.m[i][k] == 0 ) continue;
for(int j = 1; j<=res.col; ++j)
{
if(b.m[k][j] == 0 ) continue;
res.m[i][j] = (1LL *a.m[i][k]*b.m[k][j] + res.m[i][j])%mod;
}
}
}
return res;
}

void cal(int x)
{
for(int i=0; i<=31; ++i)
if(x & (1<<i) ) ans = pm[i]*ans;
}
void getPm()
{
pm[0] = A;
for(int i=1; i<=31; ++i)
pm[i] = pm[i-1]*pm[i-1];
}
struct sp//特殊点
{
int nk,tk;//nk为点的位置,tk为计算nk时和前面tk个数有关
int ck
;
bool operator<(const sp & o)const//按照nk排序
{
return nk<o.nk;
}
} p
;
int main()
{
//    freopen("in.txt","r",stdin);
int n,m,q,t,f
,c
,kase=0;
while(~scanf("%d%d%d",&n,&m,&q))
{
for(int i=m; i>0; --i)   scanf("%d",&f[i]);
scanf("%d",&t);
h =t;
for(int i=1; i<=t; ++i)  scanf("%d",&c[i]);
for(int i=0; i<q; ++i)
{
scanf("%d%d",&p[i].nk,&p[i].tk);
if(p[i].tk > h) h = p[i].tk;
for(int j=1; j<=p[i].tk; ++j) scanf("%d",&p[i].ck[j]);
}
sort(p,p+q);
A.init(h,h);
for(int i=1; i<=t; ++i) A.m[1][i] = c[i];
for(int i=2; i<=h; ++i)  A.m[i][i-1] = 1;
getPm();
ans.init(h,1);
for(int i = m; i > 0; --i)   ans.m[i][1] = f[i];
int last=m;
for(int i=0; i<q; ++i)
{
if( p[i].nk <=last ||  p[i].nk >n ) continue;
cal( p[i].nk-last-1);
last =  p[i].nk;
for(int j=1; j<=p[i].tk; ++j)  A.m[1][j] = p[i].ck[j];
for(int j=p[i].tk+1; j<=h; ++j) A.m[1][j] = 0;
ans  =A*ans;
}
cal(n-last);
printf("Case %d: %d\n",++kase,ans.m[1][1]);
}
return 0;
}


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