【题解】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^3\log n+qm^2\log 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\n",++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\n",++cnt,e[1]);
      }
      return 0;
}

原文地址:https://www.cnblogs.com/winlere/p/11559912.html

时间: 2024-10-10 18:55:38

【题解】HDU Homework(倍增)的相关文章

题解 HDU 3698 Let the light guide us Dp + 线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 759    Accepted Submission(s): 253 Problem Description Plain of despair was

题解——HDU 6225 littleboxes

一道非常简单的给你四个数求和 不过数据范围比较大会报long long a,b,c,d的值最大为2^62 那么其算术和最大为2^64 unsigned long long 最大值为2^64-1 所以只要卡掉一组样例就可以ac了 #include<cstdio> #include <iostream> using namespace std; int main() { int n; cin >> n; unsigned long long a, b, c, d; whil

【bzoj4242】水壶 BFS+最小生成树+倍增LCA

题目描述 JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有P个,编号为1...P. JOI君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外. JOI君因为各种各样的事情,必须在各个建筑物之间往返.虽然建筑物中的冷气设备非常好,但原野上的日光十分强烈,因此在原野上每走过一个区域都需要1单位的水.此外,原野上没有诸如自动售货机.饮水处之类的东西,因此IOI市的市民一般都携带水壶出

【BZOJ4569】[Scoi2016]萌萌哒 倍增+并查集

[BZOJ4569][Scoi2016]萌萌哒 Description 一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2...Sr1与Sl2Sl2+1Sl2+2...Sr2完全相同.比如n=6时,某限制条件l1=1,r1=3,l2=4,r2=6,那么123123,351351均满足条件,但是12012,131141不满足条件,前者数

【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作,每次为一下三种之一: RELEASE x:对x执行一次感染: RECENTER x:把根节点改为x,并对原来的根节点执行一次感染: REQUEST x:询问x子树中所有节点感染代价的平均值. 输入 输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数.接下来n-1行,

【9018:1893】牧场行走

问题 C: 牧场行走 时间限制: 1 Sec  内存限制: 128 MB提交: 74  解决: 36[提交][状态][讨论版] 题目描述 农场主奶牛有N个约翰,被标记为1到n,在同样被标记1到n的n块土地上吃草,第i头约翰在第i块牧场吃草. 这n块土地被n-1条路连接. 约翰可以在路上行走,第i条路连接第Ai,Bi块牧场,第i条路的长度是Li这些路被安排成任意两个约翰都可以通过这些路到达的情况,所以说这是一棵树. 这些约翰是非常喜欢交际的,经常会去互相访问,他们想让你去帮助他们计算Q对约翰之间的

【BZOJ4281】[ONTAK2015]Zwi?zek Harcerstwa Bajtockiego LCA

[BZOJ4281][ONTAK2015]Zwi?zek Harcerstwa Bajtockiego Description 给定一棵有n个点的无根树,相邻的点之间的距离为1,一开始你位于m点.之后你将依次收到k个指令,每个指令包含两个整数d和t,你需要沿着最短路在t步之内(包含t步)走到d点,如果不能走到,则停在最后到达的那个点.请在每个指令之后输出你所在的位置. Input 第一行包含三个正整数n,m,k(1<=m<=n<=1000000,1<=k<=1000000).

C++之路进阶——LCA(货车运输)

3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入描述 Input Description 第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和

poj 2492(并查集)

题意:有一个科学家提出了一个假设,一种虫子只有异性恋,而不是同性恋,然后开始实验来验证猜想,给出了n个虫子,编号从1到n,给出了q组恋爱虫子的编号,问是否验证猜想. 题解:数组倍增,给每个虫子一个异性恋的对象集合,然后每次输入的两个虫子如果不在同一个集合内,就放到对方异性恋集合内,否则无法验证猜想. #include <stdio.h> const int N = 4005; int n, q, pa[N]; int get_parent(int x) { return x == pa[x]