[bzoj4026]dC Loves Number Theory_主席树_质因数分解_欧拉函数
dC Loves Number Theory
题目大意:dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源。 给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所有元素乘积的φ(φ(n)代表1~n 中与n互质的数的个数) 。由于答案可能很大,所以请对答案 mod 10^6 + 777。 (本题强制在线,所有询问操作的l,r都需要 xor上一次询问的答案 lastans,初始时,lastans = 0)
数据范围:1<=N<=50000,1<=Q<=100000,1<=Ai<=10^6。
题解:
完全不会.....
听了$lijinnn$讲了才明白。
有一个非常非常重要的性质,如果没发现的话根本做不了。
我们考虑暴力怎么搞:每次全扫一遍,然后统计答案。
这也太暴力了....我们优化优化。
这样,每个位置开一个长度最多为$7$的数组表示当前位置的质因子因为我们知道:
$\varphi(n) = n*\prod\limits_{p_i|n} \frac{p_i - 1}{p_i}$。
这复杂度是$O(n^2\times 7)$的。
再优化优化???
发现,对于每个左端点,我可以维护处每个质因子在当前左端点右边最靠左出现的位置。
就是先扫一遍整个数组,先求出来左端点在$1$时,每个质数最左出现的位置。
接着每次,左端点往右动,更新当前左端点所在位置的值的所有质因子的答案即可,这样再查询就是在左端点对应的数组上查就好了,这是$O(n)$的。
好,现在的复杂度到了$O(n^2)$,重点就是维护每个质因子在不超过左端点的情况下,最左的位置。
那正解不就出来了么!
我们发现,左端点每动一次,更改的值只有最多$7$个,剩下的值都是相同的。
什么东西可以维护这个?就是一大堆都一样,只有几个不同
主席树呀,我们对每个左端点开一棵主席树,直接维护刚才说的数组。
咋维护呢?
就是对于第$i$颗主席树,如果有一个质数$p$在$i$左侧最左的位置是$j$,那就在主席树$j$的位置$*=\frac{p - 1}{p}$,然后主席树节点维护所支配区间所有数乘积。
但是,每个点单独质因数分解是$O(n\sqrt{a_i})$的,我们通过预处理质数,然后枚举质数的方式就好啦,复杂度是调和级数$O(nln\ n)$。
主席树的复杂度是$O(nlogn)$,每次$O(loglogn)$次,总复杂度是$O(nlognloglogn + nln\ n)$。
代码:
#include <bits/stdc++.h>
#define N 50010
using namespace std;
const int mod = 1000777 ;
typedef long long ll;
vector <int> v[1000010 ];
int prime[1000010 ], cnt;
bool vis[1000010 ];
int pre[1000010 ], bfr[N], a[N];
int ls[N * 200], rs[N * 200], sum[N * 200], root[N * 200], tot;
char *p1, *p2, buf[100000];
#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )
int rd() {
int x = 0, f = 1;
char c = nc();
while (c < 48) {
if (c == '-')
f = -1;
c = nc();
}
while (c > 47) {
x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
}
return x * f;
}
int qpow(int x, int y) {
int ans = 1;
while (y) {
if (y & 1)
ans = (ll)ans * x % mod;
y >>= 1;
x = (ll)x * x % mod;
}
return ans;
}
void init() {
for (int i = 2; i <= 1000000; i ++ ) {
if (!vis[i])
prime[ ++ cnt] = i;
for (int j = 1; j <= cnt && (ll)i * prime[j] <= 1000000; j ++ ) {
vis[i * prime[j]] = true;
if (i % prime[j] == 0) {
break;
}
}
}
}
void update(int x, int val, int l, int r, int pre, int &p) {
p = ++tot;
ls[p] = ls[pre];
rs[p] = rs[pre];
sum[p] = (ll)sum[pre] * val % mod;
if (l == r) {
return;
}
int mid = (l + r) >> 1;
if (x <= mid)
update(x, val, l, mid, ls[pre], ls[p]);
else
update(x, val, mid + 1, r, rs[pre], rs[p]);
}
int query(int x, int y, int l, int r, int p) {
if (!p) {
return 1;
}
if (x <= l && r <= y) {
return sum[p];
}
int ans = 1, mid = (l + r) >> 1;
if (x <= mid)
ans = (ll)ans * query(x, y, l, mid, ls[p]) % mod;
if (mid < y)
ans = (ll)ans * query(x, y, mid + 1, r, rs[p]) % mod;
return ans;
}
int main() {
int n = rd(), m = rd();
for (int i = 1; i <= n; i ++ ) {
a[i] = rd();
}
bfr[0] = 1;
for (int i = 1; i <= n; i ++ ) {
bfr[i] = (ll)bfr[i - 1] * a[i] % mod;
}
init();
for (int i = 1; i <= cnt; i ++ ) {
for (int j = prime[i]; j <= 1000000; j += prime[i]) {
v[j].push_back(i);
}
}
// cout << prime[cnt] << endl ;
// for (int i = 1; i <= n; i ++ ) {
// int len = v[a[i]].size();
// for (int j = 0; j < len; j ++ ) {
// printf("%d ",prime[v[a[i]][j]]);
// }
// puts("");
// }
sum[0] = 1;
for (int i = 1; i <= n; i ++ ) {
int len = v[a[i]].size();
for (int j = 0; j < len; j ++ ) {
if (pre[v[a[i]][j]]) {
update(pre[v[a[i]][j]], (ll)prime[v[a[i]][j]] * qpow(prime[v[a[i]][j]] - 1, mod - 2) % mod, 1, n, (root[i] ? root[i] : root[i - 1]), root[i]);
}
update(i, (ll)(prime[v[a[i]][j]] - 1) * qpow(prime[v[a[i]][j]], mod - 2) % mod, 1, n, (root[i] ? root[i] : root[i - 1]), root[i]);
// printf("Shit %d\n",v[a[i]][j]);
pre[v[a[i]][j]] = i;
}
}
// cout << sum[root[1]] << endl ;
// cout << (ll)sum[root[1]] * 3 % mod * qpow(2, mod - 2) % mod << endl ;
// cout << sum[root[4]] << endl ;
// cout << (ll)sum[root[4]] * 2 * 6 * 4 % mod * qpow(3, mod - 2) % mod * qpow(2, mod - 2) % mod * qpow(5, mod - 2) % mod * qpow(7, mod - 2) % mod << endl ;
// puts("Fuck");
int lastans = 0;
for (int i = 1; i <= m; i ++ ) {
int x = rd(), y = rd();
x ^= lastans, y ^= lastans;
if (x > y) {
lastans = 1;
puts("0");
continue;
}
// cout << (ll)bfr[y] * qpow(bfr[x - 1], mod - 2) % mod << endl ;
lastans = (ll)bfr[y] * qpow(bfr[x - 1], mod - 2) % mod * query(x, y, 1, n, root[y]) % mod;
printf("%d\n", lastans);
}
return 0;
}
小结:真的是好题啊,重要的是那个性质能不能发现。主席树的运用也非常巧妙。
[bzoj4026]dC Loves Number Theory_主席树_质因数分解_欧拉函数的更多相关文章
- [BZOJ4026]dC Loves Number Theory(线段树)
根据欧拉函数的定义式可知,可以先算出a[l]*a[l+1]*...*a[r]的值,然后枚举所有存在的质因子*(p-1)/p. 发现这里区间中一个质因子只要计算一次,所以指计算“上一个同色点在区间外”的 ...
- BZOJ 4026 dC Loves Number Theory (主席树+数论+欧拉函数)
题目大意:给你一个序列,求出指定区间的(l<=i<=r) mod 1000777 的值 还复习了欧拉函数以及线性筛逆元 考虑欧拉函数的的性质,(l<=i<=r),等价于 (p[ ...
- bzoj 4026 dC Loves Number Theory 主席树+欧拉函数
题目描述 dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源.给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所有元素乘积的φ(φ(n)代 ...
- [BZOJ4026]dC Loves Number Theory 欧拉函数+线段树
链接 题意:给定长度为 \(n\) 的序列 A,每次求区间 \([l,r]\) 的乘积的欧拉函数 题解 考虑离线怎么搞,将询问按右端点排序,然后按顺序扫这个序列 对于每个 \(A_i\) ,枚举它的质 ...
- BZOJ4026: dC Loves Number Theory
Description dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯 竭的水题资源. 给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所 ...
- 【bzoj3512】DZY Loves Math IV 杜教筛+记忆化搜索+欧拉函数
Description 给定n,m,求\(\sum_{i=1}^{n}\sum_{j=1}^{m}\varphi(ij)\)模10^9+7的值. Input 仅一行,两个整数n,m. Output 仅 ...
- [Cometoj#4 C]方块切割_质因数分解_贪心
方块切割 题目链接:https://cometoj.com/contest/39/problem/C?problem_id=1583 数据范围:略. 题解: 首先,如果我们知道了多少道在行上,多少刀在 ...
- 【BZOJ4026】dC Loves Number Theory 分解质因数+主席树
[BZOJ4026]dC Loves Number Theory Description dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源. 给 ...
- BZOJ_4026_dC Loves Number Theory _主席树+欧拉函数
BZOJ_4026_dC Loves Number Theory _主席树+欧拉函数 Description dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯 竭 ...
随机推荐
- 关于单片机特殊功能寄存器(SFR)和内存(RAM)公用地址:80-FF 如何区分
RAM 的 80-FF 需要间接寻址进行访问 如: MOV R0,#80H; MOV A,@R0 ; (内存 80H地址内的数据放到A中) SFR的80-FF需要直接寻址进行访问如: MOV ...
- offset([coordinates])
offset([coordinates]) 概述 获取匹配元素在当前视口的相对偏移. 返回的对象包含两个整型属性:top 和 left,以像素计.此方法只对可见元素有效.大理石平台价格表 参数 coo ...
- [Luogu] 花神游历各国
https://www.luogu.org/problemnew/show/P4145 线段树区间求和 + 区间开根号 对1e9的数开根号下取整用不了几次就会<=1 因此暴力开根号,记录区间最大 ...
- 【luoguP4124 】[CQOI2016]手机号码
题目描述 人们选择手机号码时都希望号码好记.吉利.比如号码中含有几位相邻的相同数字.不含谐音不吉利的数字等.手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售.为了便于前 ...
- g++版本低于4.7使用C++11
编译时需要添加: 需要添加头文件#include<memory> g++ -std=gnu++0x share_ptr.cpp -o s 原文: C++11 features are av ...
- Dean and Schedule (URAL 2026)
Problem A new academic year approaches, and the dean must make a schedule of classes for first-year ...
- Manjaro XFCE 设置分辨率1920*1080
#查看系统显示器名称 xrandr #自定义cvt 1920 1080 #设置分辨率xrandr --newmode "1920x1080_60.00" 173.00 1920 2 ...
- 6.RabbitMQ--事物
RabbitMQ之消息确认机制 如何防止消息丢失? 如何防止消息是否正确送达? 有些业务场景需要我们对于消息的幂等性要求是比较高的,需要消息不能丢失,在使用RabbitMQ的时候,我们可以通过消息持久 ...
- 删除Linux系统多余的引导
问题: 电脑中安装了多个Linux系统,需要删除不用的Linux系统的引导 解决方法: open terminal: su - 切换root用户 cd /boot/ ls ... grub ...
- 初写C#的小总结
虽然大学学过很多计算机语言,但是现在工作是前端,一个刚入行的前端菜鸟,之前对于后台完全零接触,但是最近有个项目,我也是第一次真正接触C#,中间遇到了一些小问题,就做个总结记录下,真的是超级简单的小知识 ...