• 【题解】HDU Homework(倍增)


    【题解】HDU Homework(倍增)

    矩阵题一定要多多检查一下是否行列反了...

    一百个递推项一定要存101个

    说多了都是泪啊

    一下午就做了这一道题因为实在是太菜了太久没写这种矩阵的题目...

    设一个行向量(e),和一个增逛矩阵(A),他们咋定义的见我那篇讲线性递推博客

    现在我们再预处理(st)矩阵数组,其中(st_i=A^{2^i})

    考虑这样一种做法,我们考虑让(e)总共有101个值,然后当第一个值被增逛为(f_{q.n-100})时,暴力将(e)中的第(101)项修改。中间的转移直接利用这个倍增数组。中间的转移由于是倍增,而且是行乘以一个矩阵,这样的话复杂度就是(O(m^2))。考虑一个询问就要处理一次最终复杂度(O(m^3log n+qm^2log n))

    细节要处理一下

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    
    using namespace std;  typedef long long ll;
    inline int qr(){
          register int ret=0,f=0;
          register char c=getchar();
          while(c<48||c>57)f|=c==45,c=getchar();
          while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
          return f?-ret:ret;
    }
    const int maxn=1e2+3;
    const int mod=1e9+7;
    int n,m,q,T;
    const int M=101;
    struct MAT{
          int data[maxn][maxn];
          MAT(){memset(data,0,sizeof data);}
          inline int*operator [](int x){return data[x];}
          inline MAT operator *(MAT&f){
    	    MAT ret;
    	    for(int k=1;k<=M;++k)
    		  for(int t=1;t<=M;++t)
    			for(int i=1;i<=M;++i)
    			      ret[t][i]=(ret[t][i]+1ll*data[t][k]*f[k][i])%mod;
    	    return ret;
          }
    }st[31];
    
    struct line{
          int data[maxn];
          line(){memset(data,0,sizeof data);}
          inline int&operator[](int x){return data[x];}
          inline line operator *(MAT&f){
    	    line ret;
    	    for(int i=1;i<=M;++i)
    		  for(int t=1;t<=M;++t)
    			ret[t]=(ret[t]+1ll*data[i]*f[i][t])%mod;
    	    return ret;
          }
    }e;
    
    int init[maxn];
    pair<pair<int,int>,vector<int> > Q[maxn];
    
    inline void pow(const int&num){
          for(int t=0;t<30;++t)
    	    if(num>>t&1)
    		  e=e*st[t];
    }
    
    int main(){
          int cnt=0;
          while(~scanf("%d%d%d",&n,&m,&q)){
    	    memset(st[0].data,0,sizeof st[0].data);
    	    memset(e.data,0,sizeof e.data);
    	    for(int t=1;t<=m;++t) e[t]=init[t]=qr()%mod;
    	    for(int t=1;t<M;++t) st[0][t+1][t]=1;
    	    T=qr();
    	    for(int t=1;t<=T;++t) st[0][M-t+1][M]=qr()%mod;
    	    for(int t=1;t<30;++t) st[t]=st[t-1]*st[t-1];
    	    for(int t=1;t<=q;++t){
    		  Q[t].first.first=qr();
    		  Q[t].first.second=qr();
    		  Q[t].second.clear();
    		  Q[t].second.push_back(0);
    		  for(int i=1;i<=Q[t].first.second;++i) Q[t].second.push_back(qr());
    	    }
    	    sort(Q+1,Q+q+1);
    	    int l=1;
    	    for(int t=m+1;t<=M;++t){
    		  if(t==Q[l].first.first&&l<=q){
    			int ret=0;
    			for(int i=1;i<=Q[l].first.second;++i)
    			      ret=(ret+1ll*init[t-i]*Q[l].second[i])%mod;
    			init[t]=ret;
    			++l;
    		  }
    		  else {
    			int ret=0;
    			for(int i=1;i<=T;++i)
    			      ret=(ret+1ll*init[t-i]*st[0][M-i+1][M])%mod;
    			init[t]=ret;
    		  }
    	    }
    	    for(int t=1;t<=M;++t) e[t]=init[t];
    	    if(n<=M) {printf("Case %d: %d
    ",++cnt,init[n]); continue;}
    	    int cur=1;
    	    for(;l<=q;++l){
    		  if(Q[l].first.first>n) break;
    		  pow(Q[l].first.first-(cur+M-1));
    		  cur+=Q[l].first.first-(cur+M-1);
    		  e[M]=0;
    		  for(int t=1;t<=Q[l].first.second;++t)
    			e[M]=(e[M]+1ll*Q[l].second[t]*e[M-t])%mod;
    	    }
    	    pow(n-cur);
    	    printf("Case %d: %d
    ",++cnt,e[1]);
          }
          return 0;
    }
    
    
  • 相关阅读:
    Andoird注册功能
    android注册功能
    寒假周总结六
    android登录功能
    Android登录功能
    android登录功能
    每日日报2021.1.24
    每日博客2021.1.23
    每日日报2021.1.22
    每日日报2021.1.21
  • 原文地址:https://www.cnblogs.com/winlere/p/11559912.html
Copyright © 2020-2023  润新知