zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",prn);
      return 0;
    }
  • 相关阅读:
    模板为webpack的目录结构
    实例和内置组件
    微信小程序之富文本解析
    微信小程序获取输入框(input)内容
    for循环的语法和执行顺序
    循环
    选择结构(二)
    选择结构
    算术运算
    变量
  • 原文地址:https://www.cnblogs.com/Narh/p/10910674.html
Copyright © 2011-2022 走看看