[BZOJ4026]dC Loves Number Theory

试题描述

dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源。

给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所有元素乘积的φ(φ(n)代表1~n 中与n互质的数的个数) 。由于答案可能很大,所以请对答案 mod 10^6 + 777。 (本题强制在线,所有询问操作的l,r都需要 xor上一次询问的答案 lastans,初始时,lastans = 0)

输入

第一行,两个正整数,N,Q,表示序列的长度和询问的个数。

第二行有N 个正整数,第i个表示Ai.

下面Q行,每行两个正整数,l r,表示询问[l ^ lastans,r ^ lastans]内所有元素乘积的φ

输出

Q行,对于每个询问输出一个整数。

输入示例

5 10
3 7 10 10 5
3 4
42 44
241 242
14 9
1201 1201
0 6
245 245
7 7
6 1
1203 1203

输出示例

40
240
12
1200
2
240
4
4
1200
4

数据规模及约定

1 <= N <= 50000

1 <= Q <= 100000

1 <= Ai <= 10^6

题解

把原序列中每个数 Ai 拆成不超过 logAi 个质因数,然后思路基本和上一题一样,只不过维护的东西换了(提示:想想怎么求 φ)。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
	if(Head == Tail) {
		int l = fread(buffer, 1, BufferSize, stdin);
		Tail = (Head = buffer) + l;
	}
	return *Head++;
}
int read() {
	int x = 0, f = 1; char c = Getchar();
	while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); }
	while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); }
	return x * f;
}

#define maxn 800010
#define maxnode 12800010
#define maxp 1000010
#define maxlog 20
#define MOD 1000777
#define LL long long

int A[maxn], nn, pos[maxn], lstp[maxp], Mulsum[maxn], inv[MOD];
void gcd(int a, int b, int& x, int& y) {
	if(!b){ x = 1; y = 0; return ; }
	gcd(b, a % b, y, x); y -= a / b * x;
	return ;
}
int Inv(int a) {
	int x, y;
	gcd(a, MOD, x, y);
	return (x % MOD + MOD) % MOD;
}
int prime[maxp], cnt, val[maxp], nxt[maxp], tval[maxlog];
bool vis[maxp];
void prime_table() {
	for(int i = 2; i <= maxp - 10; i++) {
		if(!vis[i]) prime[++cnt] = i, val[i] = prime[cnt], nxt[i] = i;
		for(int j = 1; j <= cnt && i * prime[j] <= maxp - 10; j++) {
			vis[i*prime[j]] = 1;
			val[i*prime[j]] = prime[j]; nxt[i*prime[j]] = i;
			if(i % prime[j] == 0) break;
		}
	}
	return ;
}

int ToT, rt[maxn], Mul[maxnode], lc[maxnode], rc[maxnode];
void update(int& y, int x, int l, int r, int p, int v) {
	if(v > 1) Mul[y = ++ToT] = ((LL)Mul[x] * (v - 1) % MOD) * inv[v] % MOD;
	else Mul[y = ++ToT] = Mul[x];
//	printf("%d %d %d: %d(%d %d %d)\n", y, l, r, Mul[y], x, v, inv[v]);
	if(l == r) return ;
	int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
	if(p <= mid) update(lc[y], lc[x], l, mid, p, v);
	else update(rc[y], rc[x], mid + 1, r, p, v);
	return ;
}
LL query(int o, int l, int r, int qr) {
	if(!o) return 1;
	if(r <= qr) return Mul[o];
	int mid = l + r >> 1;
	LL ans = query(lc[o], l, mid, qr);
	if(qr > mid) (ans *= query(rc[o], mid + 1, r, qr)) %= MOD;
	return ans;
}

int ANS[maxn], len;
char Out[maxn];
int main() {
//	freopen("data.in", "r", stdin);
//	freopen("data.out", "w", stdout);
	for(int i = 0; i < MOD; i++) inv[i] = Inv(i);
	prime_table();
	int n = read(), q = read();
	Mulsum[0] = 1;
	for(int i = 1; i <= n; i++) {
		int tmp = read();
		Mulsum[i] = (LL)Mulsum[i-1] * tmp % MOD;
		pos[i] = nn + 1;
		if(tmp == 1) A[++nn] = 1;
		else {
			int j = tmp, tc = 0;
			for(; nxt[j] != j; j = nxt[j]) tval[++tc] = val[j];
			tval[++tc] = val[j];
			tc = unique(tval + 1, tval + tc + 1) - tval - 1;
			for(j = 1; j <= tc; j++) A[++nn] = tval[j];
		}
	}
	pos[n+1] = nn + 1;
	n = nn; Mul[0] = 1;
	for(int i = 1; i <= n; i++) {
		update(rt[i], rt[i-1], 0, n, lstp[A[i]], A[i]);
		lstp[A[i]] = i;
	}
	/*printf("n: %d\n", n);
	for(int i = 1; i <= n; i++) printf("%d%c", A[i], i < n ? ‘ ‘ : ‘\n‘);
	for(int i = 1; i <= n; i++) printf("%d ", pos[i]); putchar(‘\n‘);*/
	int lst = 0;
	for(int i = 1; i <= q; i++) {
		int ql = read() ^ lst, qr = read() ^ lst;
		int l = pos[ql], r = pos[qr+1] - 1;
		int Multi = (LL)Mulsum[qr] * inv[Mulsum[ql-1]] % MOD;
//		printf("Multi: %d %d %d %d %d\n", Multi, rt[r], rt[l-1], query(rt[r], 0, n, l - 1), query(rt[l-1], 0, n, l - 1));
		lst = (query(rt[r], 0, n, l - 1) * inv[query(rt[l-1],0,n,l-1)] % MOD) * Multi % MOD;
		ANS[i] = lst;
//		lst = 0;
	}
	int num[10], cntn;
	for(int i = 1; i <= q; i++) {
		int tmp = ANS[i];
//		printf("%d\n", ANS[i]);
		if(!tmp) Out[len++] = ‘0‘;
		cntn = 0;
		while(tmp) num[++cntn] = tmp % 10, tmp /= 10;
		for(int j = cntn; j; j--) Out[len++] = num[j] + ‘0‘;
		if(i < q) Out[len++] = ‘\n‘; else Out[len++] = ‘\0‘;
	}
	puts(Out);

	return 0;
}

不知为何把求逆元的部分都改成 long long 交到大视野上就 T 飞,害得我差点调了一年。。。

时间: 2024-10-28 04:25:34

[BZOJ4026]dC Loves Number Theory的相关文章

【bzoj4026】dC Loves Number Theory 可持久化线段树

题目描述 dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源. 给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所有元素乘积的φ(φ(n)代表1~n 中与n互质的数的个数) .由于答案可能很大,所以请对答案 mod 10^6 + 777. (本题强制在线,所有询问操作的l,r都需要 xor上一次询问的答案 lastans,初始时,lastans = 0) 输入 第一行,两个正整数,N,Q,表示序列的长度和询问的个数. 第二行有N 个正

BZOJ 4026 dC Loves Number Theory 分块+十字链表/可持久化线段树

题目大意:给定一个序列,多次询问某段区间乘积的φ值对1000777的模 我竟然卡过去了233333 将序列分块,记录fi,j表示第i块左端点到第j个点中出现的所有质数p的p?1p之积 每次询问[x,y],首先取出[x,y]区间内所有数的积,然后乘上fst,y(其中st是x后面第一个块端点所在块) 现在还剩[x,l[st]]部分没有统计 由于106以内的数分解得到的不同的质因数最多只有7个,因此暴力枚举零碎部分的质数即可 现在对于每个质数我们需要判断是否出现过 我们只需要判断这个质数下一次出现的位

bzoj 4026 dC Loves Number Theory (主席树+数论+欧拉函数)

题目大意:给你一个序列,求出指定区间的(l<=i<=r) mod 1000777 的值 还复习了欧拉函数以及线性筛逆元 考虑欧拉函数的的性质,(l<=i<=r),等价于 (p[j]是区间内所有出现过的质数) 那么考虑找出区间内所有出现过的质数,这思路和HH的项链是不是很像?? 由于此题强制在线,所以把树状数组替换成了主席树而已 原来我以前写的主席树一直都是错的......还好推出了我原来错误代码的反例 在继承上一个树的信息时,注意不要破坏现在的树 1 #include <cs

hdu-2685I won&#39;t tell you this is about number theory(数论)

题目链接: I won't tell you this is about number theory Problem Description To think of a beautiful problem description is so hard for me that let's just drop them off. :)Given four integers a,m,n,k,and S = gcd(a^m-1,a^n-1)%k,calculate the S. Input The fi

Acdream 1114 Number theory 莫比乌斯反演

http://acdream.info/problem?pid=1114 题目大意,给你一个序列a,求出这个序列中互质数的有多少对.其中所有的整数的都小于等于222222. f(d) 为 gcd 恰好为 d 的数的对数, F(d) 为 gcd 为 d 的倍数的对数, μ(d) 表示莫比乌斯函数 F(d) = ∑ f(n) 其中( n % d == 0 ) 莫比乌斯反演一下就可以得到, f(d) = ∑ μ(n / d) * F(n) 其中( n % d == 0) 所以我们最后所要的答案就是 f

2013年北京师范大学新生程序设计竞赛网络赛--D. Number theory(模拟取余)

D. Number theory Time Limit: 1000ms Case Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main Submit Status PID: 34055 Font Size:  +   - 数学不仅是简单而且是美的.数学很有趣,但是数学中也有很多难题,比如哥德巴赫猜想.各种欧拉定理.拉格朗日中值定理.费马定理等.今天小若遇

hdu 2685 I won&#39;t tell you this is about number theory

#include<stdio.h>#include<string.h>#define LL __int64 LL mult_mod(LL a,LL b,LL c){    a%=c;    b%=c;    LL ret=0;    while(b)    {        if(b&1){ret+=a;ret%=c;}        a<<=1;        if(a>=c)a%=c;        b>>=1;    }    retur

Number Theory(数论-对数)

X - Number Theory Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Description Factorial of an integer is defined by the following function f(0) = 1 f(n) = f(n - 1) * n, if(n > 0) So, factorial of 5 is 120. B

A1-2017级算法上机第一次练习赛 P ModricWang&#39;s Number Theory II

题目描述 ModricWang has found a list containing n numbers. He calls a list bad if and only if it is not empty and gcd (see notes section for more information) of numbers in the list is 1. ModricWang can perform two types of operations: Choose a number an