传送门


这题除了暴力踩标程和正解卡常数以外是道很好的题目

首先看到我们要求的东西与\(Fibonacci\)有关,考虑矩阵乘法进行维护。又看到\(n \leq 30000\),这告诉我们正解算法其实比较暴力,又因为直接在线解决看起来就比较麻烦,所以考虑离线询问,莫队解决。

我们设斐波那契数列的转移矩阵为\(T = \left( \begin{array}{ccc} 0 & 1 \\ 1 & 1 \end{array} \right)\)

先将\(a\)离散化,用一棵线段树维护矩阵运算。那么我们需要支持的是:插入一个数并使比它大的数对应的\(Fibonacci\)数向后移一个。这个可以在线段树的对应节点打上一个\(T\)的标记,表示向右转移一个,经过这个节点时pushdown下去。删除一个数就打上它的逆矩阵的标记。总复杂度为\(O(n\sqrt{n}logn)\)

Tips:如果你TLE在了第35个点,请尽力卡常,简化取模过程、避免不必要运算(详见代码中pushup过程)

#include<bits/stdc++.h>
//This code is written by Itst
#define lch (x << 1)
#define rch (x << 1 | 1)
#define mid ((l + r) >> 1)
using namespace std;inline int read(){int a = 0;char c = getchar();bool f = 0;while(!isdigit(c)){if(c == '-')f = 1;c = getchar();}while(isdigit(c)){a = (a << 3) + (a << 1) + (c ^ '0');c = getchar();}return f ? -a : a;
}const int MAXN = 3e4 + 7;
int step = 0 , N , M , Q , T , cnt , num[MAXN] , lsh[MAXN] , times[MAXN] , ans[MAXN];
struct query{int ind , l , r;bool operator <(const query a)const{return l / T == a.l / T ? ((l / T) & 1 ? r > a.r : r < a.r) : l < a.l;}
}now[MAXN];
struct matrix{int a[2][2];int* operator [](int x){return a[x];}matrix(bool f = 1){if(f) memset(a , 0 , sizeof(a));}matrix operator *(matrix b){matrix c;for(int i = 0 ; i < 2 ; ++i)for(int j = 0 ; j < 2 ; ++j)for(int k = 0 ; k < 2 ; ++k)c[i][j] += a[i][k] * b[k][j];for(int i = 0 ; i < 2 ; ++i)for(int j = 0 ; j < 2 ; ++j)c[i][j] %= M;return c;}matrix operator *(int b){matrix c(0);for(int i = 0 ; i < 2 ; ++i)for(int j = 0 ; j < 2 ; ++j)c[i][j] = a[i][j] * b;return c;}matrix operator +(matrix b){matrix c(0);for(int i = 0 ; i < 2 ; ++i)for(int j = 0 ; j < 2 ; ++j)c[i][j] = (a[i][j] + b[i][j]) % M;return c;}bool operator ==(matrix b){for(int i = 0 ; i < 2 ; ++i)for(int j = 0 ; j < 2 ; ++j)if(a[i][j] != b[i][j])return 0;return 1;}bool operator !=(matrix b){return !(*this == b);}
}F , E , G , a , b;
struct node{matrix ans , mark;int times;
}Tree[MAXN << 2];inline void mark(int x , const matrix mark){Tree[x].mark = Tree[x].mark * mark;Tree[x].ans = Tree[x].ans * mark;
}inline void pushdown(int x){if(Tree[x].mark != E){mark(lch , Tree[x].mark);mark(rch , Tree[x].mark);Tree[x].mark = E;}
}inline void pushup(int x){a = Tree[lch].ans;b = Tree[rch].ans;if(Tree[lch].times != 1)a = a * Tree[lch].times;if(Tree[rch].times != 1)b = b * Tree[rch].times;Tree[x].ans = a + b;
}void insert(int x , int l , int r , int tar){if(l == r){Tree[x].times = lsh[tar];return; }pushdown(x);if(mid >= tar){insert(lch , l , mid , tar);mark(rch , F);}elseinsert(rch , mid + 1 , r , tar);pushup(x);
}void erase(int x , int l , int r , int tar){if(l == r){Tree[x].times = 0;return; }pushdown(x);if(mid >= tar){erase(lch , l , mid , tar);mark(rch , G);}elseerase(rch , mid + 1 , r , tar);pushup(x);
}void init(int x , int l , int r){Tree[x].times = l != r;Tree[x].mark = E;if(l != r){init(lch , l , mid);init(rch , mid + 1 , r);}elseTree[x].ans = F;
}inline void add(int a){if(!times[a]++)insert(1 , 1 , cnt , a);++step;
}inline void del(int a){if(!--times[a])erase(1 , 1 , cnt , a);++step;
}int main(){N = read();M = read();T = sqrt(N);E[0][0] = E[1][1] = F[0][1] = F[1][0] = F[1][1] = G[1][0] = G[0][1] = 1;G[0][0] = M - 1;for(int i = 1 ; i <= N ; ++i)num[i] = lsh[i] = read();sort(lsh + 1 , lsh + N + 1);cnt = unique(lsh + 1 , lsh + N + 1) - lsh - 1;for(int i = 1 ; i <= N ; ++i)num[i] = lower_bound(lsh + 1 , lsh + cnt + 1 , num[i]) - lsh;for(int i = 1 ; i <= cnt ; ++i)lsh[i] %= M;Q = read();for(int i = 1 ; i <= Q ; ++i){now[i].ind = i;now[i].l = read();now[i].r = read();}sort(now + 1 , now + Q + 1);int L = 1 , R = 0;init(1 , 1 , cnt);for(int i = 1 ; i <= Q ; ++i){while(R < now[i].r)add(num[++R]);while(L > now[i].l)add(num[--L]);while(R > now[i].r)del(num[R--]);while(L < now[i].l)del(num[L++]);ans[now[i].ind] = Tree[1].ans[0][1] * Tree[1].times % M;}cerr << step << endl;for(int i = 1 ; i <= Q ; ++i)printf("%d\n" , ans[i]);return 0;
}

转载于:https://www.cnblogs.com/Itst/p/10262139.html

CF633H Fibonacci-ish II 莫队、线段树、矩阵乘法相关推荐

  1. 牛客练习赛85 数学家的迷题 (带修莫队/线段树)

    题意: 1:将a[id]a[id]a[id]的值改为xxx. 2:令t=a[l]×a[l+1]×...×a[r−1]×a[r]t=a[l]×a[l+1]×...×a[r−1]×a[r]t=a[l]×a ...

  2. HDU - 5381 The sum of gcd(莫队/线段树区间合并)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的序列,再给出 mmm 次询问,每次询问需要回答区间 [L,R][L,R][L,R] 内所有子区间的 gcdgcdgcd 之和.更具体的,对于询问 ...

  3. SPOJ - DQUERY D-query(莫队/线段树+离线/主席树)

    题目链接:点击查看 题目大意:给出一个由n个数组成的序列,再给出m次查询,每次查询区间[l,r]中有多少个不同的数 题目分析:莫队模板题,直接套板子就好了 有点意思的是函数返回值为布尔类型,然后没有r ...

  4. 51nod-猴猴的比赛【莫队,线段树】

    正题 题目链接:https://www.51nod.com/Contest/Problem.html#contestProblemId=1150 题目大意 给出两颗nnn个点的树,求有多少个点(i,j ...

  5. jzoj6293-迷宫【ddp,线段树,矩阵乘法】

    正题 题目大意 一个n∗mn*mn∗m的迷宫,不能往左走,有墙,每次修改一个点或询问两个点之间的最短距离. 解题思路 考虑到nnn的值很小,所以我们可以用矩阵转移,然后要求支持修改和查询所以我们考虑d ...

  6. LOJ2980 THUSC2017大魔法师(线段树+矩阵乘法)

    线段树每个节点维护(A,B,C,len)向量,操作即是将其乘上一个矩阵. #include<iostream> #include<cstdio> #include<cma ...

  7. 牛客 - 求函数(线段树+区间合并/线段树+矩阵维护)

    题目链接:点击查看 题目大意:现在有 n 个函数,每个函数都是诸如 f( x ) = k * x + b 的形式,只是每个函数的 k 和 b 都是相互独立的,现在给出两个操作: 1 pos k b:将 ...

  8. P4113 [HEOI2012]采花 【树状数组 AC】【莫队/主席树 TLE】

    传送门 题意简述:给定一个长度为 n 的序列,有 m 次询问,每次询问一段区间,求区间中有多少个数出现次数超过 1 次 这道题真的有点恶心...在洛谷上属于莫队,但是莫队会T,数据居然有2e6.莫队的 ...

  9. Hdu 6534 Chika and Friendly Pairs 莫队算法+树状数组

    题目链接 题意求给区间[L,R]中有少对(i,j)满足i<j且abs(a[i]-a[j])<=k. 首先来说暴力的方法就是离散化,然后用树状数组来维护,但是m次询问,m很大,所以说一定会t ...

  10. leetcode 729, 731, 732. My Calendar I, II, III | 729. 我的日程安排表 I, II, III(线段树)

    729. My Calendar I https://leetcode.com/problems/my-calendar-i/ 题解 看了左神课之后,自己实现了下改造后的线段树(非常不优雅),因为数组 ...

最新文章

  1. 判断是否过期的算法_铁观音多久过期,怎么判断铁观音是否过期?
  2. 一个大浪Java罢工(一个)安装JDK和环境变量配置
  3. CentOS 6.5 x86_64升级内核到最新版2.6.32-696.1.1.el6.x86_64
  4. python for while enumerate
  5. 微信小程序python_用python一步一步教你玩微信小程序【跳一跳】
  6. 8/7排位赛,codeforces501
  7. android面试(4)---文件存储
  8. LAMP_PHP配置
  9. STM32学习记录0005——JLINK下载与调试
  10. 四象限法推导lm曲线_数据分析四象限法详解
  11. 机器人断脚_超强算法让机器人脚断了照样跑
  12. 两阶段随机规划模型简介
  13. 【数学建模】12 线性规划模型的求解方法
  14. 出现 Unexpected token T in JSON at position 0 ,at JSON.parse (<anonymous>) 的解决方法
  15. USB调试】和【未知来源】开关
  16. MySQL系统变量auto_increment_increment与auto_increment_offset学习总结
  17. 2020年你最需要掌握的11种编程语言
  18. 【Java基础学习】
  19. 考试备战系列--软考--02基础知识复习
  20. 监听Redis 缓存过期(Key 失效)事件

热门文章

  1. 随机森林 matlab
  2. 2022-2027年中国实验室自动化行业市场调研及未来发展趋势预测报告
  3. Linux中的screen命令使用
  4. 收益率的标准差怎么算MATLAB,什么是收益的标准差怎样计算呢
  5. python中判断小写字符_Python islower()函数 判断字符串中字符是否都为小写
  6. 计算机专业研究生读研规划,关于一个计算机研究生人生规划的迷惑
  7. 中兴ZXVb860av2.1t刷机固件,芯片晶晨S905l-b,不失效线刷包,当贝桌面
  8. 洛谷P3376 【模板】网络最大流{Dinic算法}
  9. Git命令使用出现Cannot update paths and switch to branch xxx at the same time解决方法
  10. otg usb 定位_怎样打开安卓手机外接USB功能(即OTG功能)