2016浙江省赛:E 题 Modulo Query

【难度】

4.5/104.5/104.5/10
据说是卡银题?感觉有点难

【题意】

F(i,X)={XmodA1i=1F(i−1,X)modAi2≤i≤NF(i,X)= \begin{cases} X\mod A_1\quad i=1\\ F(i-1,X)\mod A_i \quad 2\le i\le N \end{cases} F(i,X)={XmodA1​i=1F(i−1,X)modAi​2≤i≤N​
其中,AAA是一个长度为NNN的整数数组,
XXX是不大于MMM的非负整数。

现在给你了 N,A,M,QN,A,M,QN,A,M,Q
共QQQ组询问,每组给你一个YYY
让你求出有多少个不同的XXX满足F(N,X)=Y\color{cyan}F(N,X)=YF(N,X)=Y

对于第 iii 个询问,若方案数为ZiZ_iZi​
则答案累加上 i×Zii\times Z_ii×Zi​
最后输出最终的累加答案取模109+710^9+7109+7即可。

【数据范围】

2≤N≤1052\le N\le 10^52≤N≤105
0≤M≤1090\le M\le 10^90≤M≤109
1≤Ai≤1091\le A_i\le 10^91≤Ai​≤109
1≤Q≤1051\le Q\le 10^51≤Q≤105
0≤Yi≤1090\le Y_i\le 10^90≤Yi​≤109

Time limit:2000 ms
Memory limit:65536 kB

【输入样例】

TTT样例组数
NMN\ MN M
A1⋯AnA_1\cdots A_nA1​⋯An​
QQQ
Y1Y_1Y1​
⋮\vdots⋮
YQY_QYQ​

1
3 5
3 2 4
5
0
1
2
3
4

【输出样例】

8

【解释】

每次查询的方案数分别为:4,2,0,0,04,2,0,0,04,2,0,0,0

【思路】

【首先考虑下暴力做法】
化简那个奇怪的递归式子,无非就是让你求:
F(N,X)=XmodA1modA2⋯modAn=YF(N,X)=X\bmod A_1\bmod A_2\cdots \bmod A_n =Y F(N,X)=XmodA1​modA2​⋯modAn​=Y
若我们暴力枚举XXX,每次都计算出该式子的YYY,对于每个查询QQQ都这么做的话:
时间复杂度为:O(N×M×Q)=1018O(N\times M\times Q)=10^{18}O(N×M×Q)=1018

若我们计算完一次之后使用 unordered_mapunordered\_mapunordered_map 记录每个数的答案的话:
时间复杂度为:O(N×M)=1014O(N\times M)=10^{14}O(N×M)=1014

易得,我们不能单纯让X暴力枚举[0,M],应该一段一段区间考虑\color{red}易得,我们不能单纯让X暴力枚举[0,M],应该一段一段区间考虑易得,我们不能单纯让X暴力枚举[0,M],应该一段一段区间考虑

【从区间考虑】

(一)考虑下面一个例子:

X属于[0,10][0,10][0,10],A1=3A_1=3A1​=3
我们简单枚举可得

YYY 查询数字 ZZZ相应答案 XXX取值
0 4 0,3,6,9
1 4 1,4,7,10
2 3 2,5,8
3 0

首先对于取模运算,易得:取模后一定比取模数要小。
Y≥min⁡i{Ai}时,Z=0(1)\color{red}Y\ge\underset{i}{\min}\{A_i\}时,Z=0\tag{1} Y≥imin​{Ai​}时,Z=0(1)
然后我们分析一下每个YYY 对应的 ZZZ 的规律。画一下图即可得知:

我们把区间[0,10][0,10][0,10] 挖成三个 [0,2][0,2][0,2]的区间和一个 [0,1][0,1][0,1]的区间。
最后计算某个YYY 的时候,我们只要计算有多少个区间是包含这个Y即可。

(二)处理区间

但是有小伙伴说:你这区间怎么快速分割呀?一遍一遍for分割时间复杂度肯定超!

我们这就等价优化一下。


操作方法:
我们把区间[0,M]转化为[1,M+1]这样,我们直接使用除法即可直接计算。最后计算Y的时候,每个区间长度再转化成从0开始的区间即可。\color{cyan}我们把区间[0,M]转化为[1,M+1]\\ \color{gray}这样,我们直接使用\pmb{除法}即可直接计算。\\ 最后计算Y的时候,每个区间长度再转化成从0开始的区间即可。 我们把区间[0,M]转化为[1,M+1]这样,我们直接使用除法除法除法即可直接计算。最后计算Y的时候,每个区间长度再转化成从0开始的区间即可。
上图的例子:M=10时,区间转化为[1,11][1,11][1,11]
遇到A1=3A_1=3A1​=3,该区间出现的小区间的段数为⌊11/3⌋=3\lfloor11/3\rfloor=3⌊11/3⌋=3
那么剩余的一个小区间的长度为 11mod3=211\bmod3=211mod3=2

更正式的语言描述:
若你现在有一个区间[1,P],该区间长为P出现的次数为tim现在有一个取模数Ai,Ai<P,那么该模数会把区间进行取模分割多出来的小区间[1,Ai]增加了⌊P/Ai⌋×tim个若Ai∤P,则多出来一个额外的小区间[1,PmodAi]增加了tim个(2)若你现在有一个区间[1,P],该区间长为\color{green}P\color{w}出现的次数为\color{green}tim\color{w}\\ 现在有一个取模数A_i,A_i<P,那么该模数会把区间进行取模分割\\ 多出来的小区间[1,A_i]增加了\color{red}\lfloor P/A_i\rfloor\times tim \color{w}个\tag{2}\\ 若 A_i\nmid P,则多出来一个额外的小区间 [1,P\bmod A_i]增加了\color{red}tim\color{w}个 若你现在有一个区间[1,P],该区间长为P出现的次数为tim现在有一个取模数Ai​,Ai​<P,那么该模数会把区间进行取模分割多出来的小区间[1,Ai​]增加了⌊P/Ai​⌋×tim个若Ai​∤P,则多出来一个额外的小区间[1,PmodAi​]增加了tim个(2)

由公式(1),若某个AiA_iAi​ 比你所拥有的区间长度还要大,那么就不必继续的区间分割了

可以使用 优先队列\color{red}优先队列优先队列完成吗?显然不行\color{red}不行不行。
若我们多出来的区间[1,Ai][1,A_i][1,Ai​]或者 [1,PmodAi][1,P\bmod A_i][1,PmodAi​] 是已有的,那么优先队列里的相同元素会越来越多。

这样,我们使用 Map\color{red}MapMap 即可。它可以轻松记录某个区间出现的次数,可以随时O(log⁡N)O(\log N)O(logN)修改增删,并且有序,可以类似优先队列优先拿出区间较大的出来。

【小技巧:】
MapMapMap 优先拿出的是第一个元素值较小的元素,若我们往里添加某个数的负数,则可以优先拿出原来元素值较大的元素。拿出来后再取反即可。

(三)处理询问

我们怎么知道某个数字在多少个之前处理的区间范围内的?

首先,我们按区间长度由小到大排列。然后记录前缀和即可。
aa[i]表示区间长度第i小的区间的长度pre[i]记录区间次数的前缀和,pre[i]=∑ij=1aa[j]的tim\color{green}aa[i]表示区间长度第i小的区间的长度\\ pre[i]记录区间次数的前缀和,pre[i]=\underset{j=1}{\overset{i}{\sum}}aa[j]的tim aa[i]表示区间长度第i小的区间的长度pre[i]记录区间次数的前缀和,pre[i]=j=1∑i​​aa[j]的tim

对于某个查询的 YYY ,我们知道该数的出现次数为:


对于某个Y,该Z=pre[Tot]−pre[L]其中Total为最大的iL=max⁡i{i∣aa[i]<Y}(3)对于某个Y,该\color{red}Z=pre[Tot]-pre[L]\color{w}\\ 其中\color{w}Total为最大的i\\ \color{red}L=\underset{i}{\max}\{i\big | aa[i]<Y\}\tag{3} 对于某个Y,该Z=pre[Tot]−pre[L]其中Total为最大的iL=imax​{i∣∣​aa[i]<Y}(3)
注意式子(3),不能取等于号。
我们使用 lower_bound\color{red}lower\_boundlower_bound 即可算出LLL

【核心代码】

时间复杂度:O(Nlog⁡N+Qlog⁡N)O(N\log N+Q\log N)O(NlogN+QlogN) 应该是很松的上界,紧上界可以看其他dl的证明
Time(ms):63 (不使用快读为278ms)
Mem(MB):1.1

/*_            __   __          _          _
| |           \ \ / /         | |        (_)
| |__  _   _   \ V /__ _ _ __ | |     ___ _
| '_ \| | | |   \ // _` | '_ \| |    / _ \ |
| |_) | |_| |   | | (_| | | | | |___|  __/ |
|_.__/ \__, |   \_/\__,_|_| |_\_____/\___|_|__/ ||___/
*/
const int MAX = 1e5+50;map<ll,ll>M;
ll aa[MAX];
ll pre[10*MAX];int main()
{int T;T = read();while(T--){M.clear();int n;ll m;n = read();m = read_ll();ll bef = m + 1LL;           /// 原区间长转化为[1,M+1]M[-bef] = 1LL;              /// 添加负数即可以每次取出最长的区间for(int i=1;i<=n;++i){ll now = read_ll();if(now >= bef)continue;        /// 公式(1)bef = now;for(map<ll, ll>::iterator it = M.begin(); it != M.end();){ll chang = -it->first;ll tim   =  it->second;if(chang <= now)break;       /// 公式(1)ll more = chang / now;ll another = chang % now;map<ll, ll>::iterator itr = it;it++;M.erase(itr);                /// erase itM[-now] += tim * more;            /// 公式(2)if(another!=0)M[-another] += tim;   /// 公式(2)}}int cnt = 0;aa[0] = 0LL;for(map<ll, ll>::reverse_iterator rit = M.rbegin(); rit != M.rend();rit++){ll chang = -rit->first - 1;           /// 倒序遍历即从小到大排序ll tim   =  rit->second;aa[++cnt] = chang;pre[cnt] = pre[cnt-1] + tim;      /// 前缀和记录}ll Q;Q = read_ll();ll Z = 0LL;for(ll i = 1;i <= Q; ++i){ll y;ll ans = 0LL;y = read_ll();if(y >= bef)continue;          /// 公式(1)ll di = lower_bound(aa,aa+cnt+1,y) - aa;if(di && aa[di] >= y)di--;Z = Z + i * (pre[cnt] - pre[di]) % MOD; /// 公式(3),乘上i是题目要求Z %= MOD;}printf("%lld\n",Z);}return 0;
}

【2016浙江省赛:区间取模】E : Modulo Query | ZOJ - 3940相关推荐

  1. 3位水仙花数计算pythonoj_简述 取模运算Modulo Operation 及其与 取余运算Complementation 区别联系...

    综述: 取模运算("Modulo Operation")和取余运算("Complementation ")两个概念有重叠的部分但又不完全一致.主要的区别在于对负 ...

  2. 2016浙江省赛过山车记

    省赛后一天就是期中考真刺激,可以体验连续滚粗的快感. 听说今天是鸟神的生日,于是凌晨造了个大新闻,强行给鸟神灌了一大口毒奶. 热身赛写模拟写到结束也没调出来,给下午滚粗奠定了坚实的基础. 正赛,打开题 ...

  3. 【CodeForces - 438D】The Child and Sequence(线段树区间取模操作)

    题干: At the children's day, the child came to Picks's house, and messed his house up. Picks was angry ...

  4. java中的取模_Java 中的取模和取余

    期末复习密码学时需要用到取模运算,发现 Java 中的 % 运算符并不是取模运算(Modulo Operation),而是取余运算(Complementation). 计算方法 对于整数 a,b 来说 ...

  5. 取模运算性质_求余、取模运算在RTOS中计算优先级的理解

    uCOS3中的部分源码: /* 置位优先级表中相应的位 */ void OS_PrioInsert (OS_PRIO prio) { CPU_DATA bit; CPU_DATA bit_nbr; O ...

  6. 取模运算性质_数学与编程——求余、取模运算及其性质 | 学步园

    一.求余运算(Remainder) http://zh.wikipedia.org/wiki/同余) Euclidean division:Given two integers a and b, wi ...

  7. python模运算求余_取模运算和取余运算

    取模运算和取余运算 取模运算( " Modulo Operation " )和取余运算 ( " Complementation " )两个概念有重叠的部分但又不 ...

  8. java取模_Java 中的取模和取余

    期末复习密码学时需要用到取模运算,发现 Java 中的 % 运算符并不是取模运算(Modulo Operation),而是取余运算(Complementation). 计算方法 对于整数 \(a\), ...

  9. [2016湘潭邀请赛 A. 2016] 大数取模+循环节

    [2016湘潭邀请赛 A. 2016] 大数取模+循环节 1. 题目链接 XTU OnlineJudge : [2016湘潭邀请赛 A. 2016] 2. 题意描述 [图片看不清可以放大.] 给定一个 ...

最新文章

  1. rabbitmq消费固定个数消息_SpringBoot+RabbitMQ (保证消息100%投递成功并被消费)
  2. 【Python学习系列五】Python网络爬虫框架Scrapy环境搭建
  3. Sublime Text3 高亮显示Jade语法 (Windows 环境)
  4. Java:汇总堆外数据
  5. java数据结构之折半查找
  6. python杀线程_python-有什么办法可以杀死线程吗?
  7. 各国网络安全审查制度及案例分析
  8. Batch normalization:accelerating deep network training by reducing internal covariate shift的笔记
  9. 维克仓库管理软件 v3.4 工程网络版 是什么
  10. Windows系统文件结构
  11. winhex添加删除字节
  12. 人在当时处境中,像旋涡中的一片落叶,身不由己
  13. 如何设置普通网页的微信分享图标
  14. 割平面算法求解整数规划
  15. 前后端鉴权方案,一文打尽!
  16. jQuery 实现消消乐
  17. 以“基”取胜:青立方超融合易捷版,助力企业“极简”上云
  18. 扇贝python_【扇贝批量添加单词到词库】利用python调用扇贝API (oauth2)
  19. k8s tekton 实现CI流程,从git到docker registry
  20. 代码生成器的使用步骤

热门文章

  1. 用Python做三角形的面积
  2. 克鲁斯卡尔(Kruskal)
  3. 一招连环追销,让顾客在第一次成交中买多个产品,客单价提高十倍
  4. php 正文提取算法,基于机器学习的网页正文提取方法
  5. 深圳市专精特新企业申报流程及奖励政策重点介绍,补贴20-50万
  6. cpe(通用平台枚举)命名规范及python CPE库实战
  7. 对于气缸型号表示的内容与与含义说明
  8. linux驱动开发之spi-omap-100k.c源码分析
  9. 例题5.23 蚂蚁 LA4043
  10. 快速增加图片大小KB