矩阵快速幂+倍增spoj8059

本文介绍了一种基于历史销售数据预测未来销售额的模型,并提供了一个程序实现示例,该程序能够根据模型预测特定间隔月份的销售总额。

E - Stocks Prediction
Time Limit:8000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu

Description

The department store where my family goes shopping is trying to predict how much of each item they stock they will sell each month.  Keeping a large amount of inventory is costly, and running out of items is also not a good idea.  Since the manager asked for my help as a sales consultant, I decided to formulate a model for predicting each month's sales S of an item based on its sales during the previous R months.  After a lot of trial and error, I came up with such a model, where 
S(n) = a1*S(n-1) + a2*S(n-2) + ... + aR*S(n-R)  
where S(n) is the predicted sales for the nth month for n > R, and S(1) to S(R) are seed values. 
 
The store manager was pleased with my model's ability to help him in controlling his inventory.  
He asked me to list out every Kth month's sales, and give him the sum of the first N values from this list.  For example he wanted every Christmas month's sales summed up for the next 10 years (N=10 and K=12, month 1 being January), or every end-of-quarter month's sales for the next 2 years (N=2, K=3). 
 
Can you please help me write a program that does all the above? 
 
INPUT 
The first line of the input T, the number of test cases. Each test case consists of three lines. 
The first line of each test case contains N, R, K. 
The second line of each test case contains R integers denoting S(1), S(2), ..., S(R). 
The third line of each test case contains R integers denoting the coefficients a1, a2, ..., aR of the predictive model. 
 
OUTPUT 
For each test case, output the sum requested by the manager as given in the problem statement, modulo 1,000,000,007. 
 
CONSTRAINTS 
T <= 40 
1 <= N <= 1000000000 
1 <= R <= 8 
1 <= K <= 8 
0 <= All other input values < 1000000007 
 
SAMPLE INPUT 

4 1 1 
1  
2  
3 2 3 
1 1  
1 1  
 
SAMPLE OUTPUT 
15 
44 
 
EXPLANATION 
In the first test case, it is given that S(1) = 1 and the relation is S(n)=2*S(n-1). The list asked by the store manager consists of all the terms of S since K is 1. Hence, the answer is just the sum of the first 4 terms of S. 
In the second test case, the sequence S is the fibonacci sequence which is: 1, 1, 2, 3, 5, 8, 13, 21, 34. The list consists of 2, 8, 34 which sum up to 44.


构造矩阵,然后倍增法求和

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=10;
const int MOD=1000000007;
typedef long long LL;
int N,K,R;
LL a[maxn],s[maxn];

struct Matrix
{
    LL mat[maxn][maxn];
    Matrix(){memset(mat,0,sizeof(mat));}
    Matrix operator *(Matrix a)
    {
        Matrix res;
        for(int i=0;i<R;i++)
            for(int j=0;j<R;j++)
            {
                for(int k=0;k<R;k++)
                {
                    res.mat[i][j]=(res.mat[i][j]+mat[i][k]*a.mat[k][j]%MOD)%MOD;
                }
            }
        return res;
    }
    Matrix operator + (Matrix a)
    {
        Matrix res;
        for(int i=0;i<R;i++)
            for(int j=0;j<R;j++)
            res.mat[i][j]=(mat[i][j]+a.mat[i][j])%MOD;
        return res;
    }

};

Matrix pow_mul(Matrix a,int x)
{
    Matrix res;
    for(int i=0;i<=R;i++)res.mat[i][i]=1;
    while(x)
    {
        if(x&1)res=res*a;
        a=a*a;
        x>>=1;
    }
    return res;
}

Matrix cal(Matrix A,int x)
{
    if(x==1)return A;
    Matrix tmp=cal(A,x/2);
    Matrix sum=(tmp+pow_mul(A,x/2)*tmp);
    if(x%2==1)
        sum=(pow_mul(A,x)+sum);
    return sum;
}

int main()
{
    freopen("in.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&N,&R,&K);
        for(int i=0;i<R;i++)scanf("%lld",&s[i]);
        for(int i=0;i<R;i++)scanf("%lld",&a[i]);
        Matrix A,B,C,D;
        for(int i=0;i<R-1;i++)A.mat[i][i+1]=1;
        for(int i=0;i<R;i++)A.mat[R-1][i]=a[R-1-i];
        for(int i=0;i<R;i++)B.mat[i][0]=s[i];
        C=pow_mul(A,K-1)*B;
        Matrix E;
        for(int i=0;i<=R;i++)E.mat[i][i]=1;
        D=(cal(pow_mul(A,K),N-1)+E)*C;
        cout<<D.mat[0][0]<<endl;
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值