bzoj 4161 Shlw loves matrixI——常系数线性齐次递推

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4161

还是不能理解矩阵……

关于不用矩阵理解的方法:https://blog.csdn.net/joker_69/article/details/80869814

关于这道题:https://blog.csdn.net/sdfzyhx/article/details/63697273

现在只会 O(k2logn) 的做法。

很多题解的写法是快速幂到多项式的 n-(k-1) 次,用递推式暴力把给出的 \(h_0,...,h_{k-1}\) 扩展到 \( h_0,...,h_{2*(k-1)} \) ,然后用 \( h_{k-1},...,h_{2*(k-1)} \) 乘上刚才做出的多项式得到答案。关于这个的理解:

  现在的多项式可以看作是转移矩阵 M 的 n-(k-1) 次幂的第一列。考虑到原来的值向量对应位乘上该多项式就是第 n-(k-1) 次项的答案,所以大概可以这样考虑?

  所以这个多项式可以在 \( h_i,...,h_{i+k-1} \) 乘上它的情况下得到 \( h_{i+n-(k-1)} \) 的答案。

但直接把多项式乘到 n 次,然后用初始的 \( h_0,...,h_{k-1} \) 来乘,在 bzoj 上似乎比上述方法稍微快一点。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
const int N=4005,mod=1e9+7;
int upt(int x){while(x>=mod)x-=mod;while(x<0)x+=mod;return x;}

int n,k,a[N],h[N],b[N],c[N],ans[N];
void Mul(int *u,int *v)
{
  memset(c,0,sizeof c);
  for(int i=0;i<k;i++)
    for(int j=0;j<k;j++)
      c[i+j]=(c[i+j]+(ll)u[i]*v[j])%mod;
  for(int i=2*(k-1);i>=k;i--)
    if(c[i])
      for(int j=1;j<=k;j++)
    c[i-j]=(c[i-j]+(ll)c[i]*a[j])%mod;
  memcpy(u,c,sizeof (int)*k);
}
int main()
{
  n=rdn();k=rdn();
  for(int i=1;i<=k;i++)a[i]=upt(rdn());//upt!!!
  for(int i=0;i<k;i++)h[i]=upt(rdn());
  if(n<k){printf("%d\n",h[n]);return 0;}
  /*for(int i=k,lm=2*(k-1);i<=lm;i++)
    for(int j=1;j<=k;j++)
      h[i]=(h[i]+(ll)a[j]*h[i-j])%mod;
      if(n<=2*(k-1)){printf("%d\n",h[n]);return 0;}*/
  b[1]=1; ans[0]=1;
  /*n-=k-1;*/
  while(n){ if(n&1)Mul(ans,b); Mul(b,b); n>>=1;}
  int prn=0;
  /*for(int i=0;i<k;i++)
    prn=(prn+(ll)h[k-1+i]*ans[i])%mod;*/
  for(int i=0;i<k;i++)
    prn=(prn+(ll)h[i]*ans[i])%mod;
  printf("%d\n",prn);
  return 0;
}

 

posted on 2019-05-23 11:00  Narh  阅读(151)  评论(0编辑  收藏

导航