zoukankan      html  css  js  c++  java
  • 【题解】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;
    }
    
    
  • 相关阅读:
    网站安全编程 黑客入侵 脚本黑客 高级语法入侵 C/C++ C# PHP JSP 编程
    【算法导论】贪心算法,递归算法,动态规划算法总结
    cocoa2dx tiled map添加tile翻转功能
    8月30日上海ORACLE大会演讲PPT下载
    【算法导论】双调欧几里得旅行商问题
    Codeforces Round #501 (Div. 3) B. Obtaining the String (思维,字符串)
    Codeforces Round #498 (Div. 3) D. Two Strings Swaps (思维)
    Educational Codeforces Round 89 (Rated for Div. 2) B. Shuffle (数学,区间)
    洛谷 P1379 八数码难题 (BFS)
    Educational Codeforces Round 89 (Rated for Div. 2) A. Shovels and Swords (贪心)
  • 原文地址:https://www.cnblogs.com/winlere/p/11559912.html
Copyright © 2011-2022 走看看