【2016浙江省赛:区间取模】E : Modulo Query | ZOJ - 3940
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)={XmodA1i=1F(i−1,X)modAi2≤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)=XmodA1modA2⋯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≥mini{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(logN)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∑iaa[j]的tim
对于某个查询的 YYY ,我们知道该数的出现次数为:
对于某个Y,该Z=pre[Tot]−pre[L]其中Total为最大的iL=maxi{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(NlogN+QlogN)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相关推荐
- 3位水仙花数计算pythonoj_简述 取模运算Modulo Operation 及其与 取余运算Complementation 区别联系...
综述: 取模运算("Modulo Operation")和取余运算("Complementation ")两个概念有重叠的部分但又不完全一致.主要的区别在于对负 ...
- 2016浙江省赛过山车记
省赛后一天就是期中考真刺激,可以体验连续滚粗的快感. 听说今天是鸟神的生日,于是凌晨造了个大新闻,强行给鸟神灌了一大口毒奶. 热身赛写模拟写到结束也没调出来,给下午滚粗奠定了坚实的基础. 正赛,打开题 ...
- 【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 ...
- java中的取模_Java 中的取模和取余
期末复习密码学时需要用到取模运算,发现 Java 中的 % 运算符并不是取模运算(Modulo Operation),而是取余运算(Complementation). 计算方法 对于整数 a,b 来说 ...
- 取模运算性质_求余、取模运算在RTOS中计算优先级的理解
uCOS3中的部分源码: /* 置位优先级表中相应的位 */ void OS_PrioInsert (OS_PRIO prio) { CPU_DATA bit; CPU_DATA bit_nbr; O ...
- 取模运算性质_数学与编程——求余、取模运算及其性质 | 学步园
一.求余运算(Remainder) http://zh.wikipedia.org/wiki/同余) Euclidean division:Given two integers a and b, wi ...
- python模运算求余_取模运算和取余运算
取模运算和取余运算 取模运算( " Modulo Operation " )和取余运算 ( " Complementation " )两个概念有重叠的部分但又不 ...
- java取模_Java 中的取模和取余
期末复习密码学时需要用到取模运算,发现 Java 中的 % 运算符并不是取模运算(Modulo Operation),而是取余运算(Complementation). 计算方法 对于整数 \(a\), ...
- [2016湘潭邀请赛 A. 2016] 大数取模+循环节
[2016湘潭邀请赛 A. 2016] 大数取模+循环节 1. 题目链接 XTU OnlineJudge : [2016湘潭邀请赛 A. 2016] 2. 题意描述 [图片看不清可以放大.] 给定一个 ...
最新文章
- rabbitmq消费固定个数消息_SpringBoot+RabbitMQ (保证消息100%投递成功并被消费)
- 【Python学习系列五】Python网络爬虫框架Scrapy环境搭建
- Sublime Text3 高亮显示Jade语法 (Windows 环境)
- Java:汇总堆外数据
- java数据结构之折半查找
- python杀线程_python-有什么办法可以杀死线程吗?
- 各国网络安全审查制度及案例分析
- Batch normalization:accelerating deep network training by reducing internal covariate shift的笔记
- 维克仓库管理软件 v3.4 工程网络版 是什么
- Windows系统文件结构
- winhex添加删除字节
- 人在当时处境中,像旋涡中的一片落叶,身不由己
- 如何设置普通网页的微信分享图标
- 割平面算法求解整数规划
- 前后端鉴权方案,一文打尽!
- jQuery 实现消消乐
- 以“基”取胜:青立方超融合易捷版,助力企业“极简”上云
- 扇贝python_【扇贝批量添加单词到词库】利用python调用扇贝API (oauth2)
- k8s tekton 实现CI流程,从git到docker registry
- 代码生成器的使用步骤