首页 > 其他分享 >P3747 [六省联考 2017] 相逢是问候

P3747 [六省联考 2017] 相逢是问候

时间:2023-03-20 21:57:49浏览次数:45  
标签:le 六省 pw 测试点 13700558 int 样例 P3747 联考

[六省联考 2017] 相逢是问候

P3747 [六省联考 2017] 相逢是问候

题目描述

Informatik verbindet dich und mich.
信息将你我连结。

B 君希望以维护一个长度为 \(n\) 的数组,这个数组的下标为从 \(1\) 到 \(n\) 的正整数。

一共有 \(m\) 个操作,可以分为两种:

  • 0 l r 表示将第 \(l\) 个到第 \(r\) 个数( \(a_l,a_{l+1} ...a_r\))中的每一个数 \(a_i\) 替换为 \(c^{a_i}\),即 \(c\) 的 \(a_i\) 次方,其中 \(c\) 是输入的一个常数,也就是执行赋值 \(a_i = c^{a_i}\)。

  • 1 l r 求第 \(l\) 个到第 \(r\) 个数的和,也就是输出: \(\sum_{i=l}^{r}a_i\)

因为这个结果可能会很大,所以你只需要输出结果 \(\bmod \space p\) 的值即可。

输入格式

第一行有四个整数 \(n, m, p, c\),所有整数含义见问题描述。
接下来一行 \(n\) 个整数,表示 \(a\) 数组的初始值。
接下来 \(m\) 行,每行三个整数,其中第一个整数表示了操作的类型。

  • 如果是 \(0\) 的话,表示这是一个修改操作,操作的参数为 \(l, r\)。
  • 如果是 \(1\) 的话,表示这是一个询问操作,操作的参数为 \(l, r\)。

输出格式

对于每个询问操作,输出一行,包括一个整数表示答案 \(\bmod \space p\) 的值。

样例 #1

样例输入 #1

4 4 7 2
1 2 3 4
0 1 4
1 2 4
0 1 4
1 1 3

样例输出 #1

0
3

样例 #2

样例输入 #2

1 40 19910626 2
0
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1

样例输出 #2

1
2
4
16
65536
11418102
18325590
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558

提示

【数据范围】

对于 \(0\%\) 的测试点,和样例一模一样;

对于另外 \(10\%\) 的测试点,没有修改;

对于另外 \(20\%\) 的测试点,每次修改操作只会修改一个位置(也就是 \(l = r\) ),并且每个位置至多被修改一次;

对于另外 \(10\%\) 的测试点, \(p = 2\);

对于另外 \(10\%\) 的测试点, \(p = 3\);

对于另外 \(10\%\) 的测试点, \(p = 4\);

对于另外 \(20\%\) 的测试点, \(1\le n,m \le 100\);

对于 \(100\%\) 的测试点, \(1\le n,m \le 5\times 10^4\),\(1 \le p \le 10^8\),\(0< c < p\),\(0 \le a_i < p\)。

Solution

首先对于题目中的修改操作,肯定是不能使用常规维护 tag 的方式进行处理的,因此尝试发现一下特殊性质。观察样例二可以发现,在进行了一定次数修改过后,\(a_i\) 的值会变成定值,因此考虑用类似区间开方的操作来解决。

回来看 \(c^a\) 这一操作。若干次操作如果同时作用于同一个 \(a_i\) 上,那么整个的式子就会变成类似这样的幂塔:\(c^{c^{.^{.^{.^{a}}}}}\)。定义 \(f(i)=c^{f(i-1)}\bmod p,f(0)=a\),那么可以对 \(f(i)\) 应用欧拉降幂:\(f(i)=c^{f(i-1)\bmod \varphi(p)+\varphi(p)}\bmod p\),然后对于这个指数可以进行递归处理,每递归一次 \(p\) 都会变成 \(\varphi(p)\),因此这样最多递归 \(\mathcal O(\log p)\) 次 \(p\) 就会变成 \(1\),此时无论 \(a\) 是什么值都不会影响结果了。

考虑将这个结论运用到此题上来,因为证明出来了一个数最多只会变 \(\mathcal O(\log p)\) 次,因此可以用与区间开方完全一样的做法进行解决。使用分块以及快速幂计算,时间复杂度 \(\mathcal O(n\sqrt{n}\log^2 p)\),可以拿到 90pts,考虑优化。

发现每次进行快速幂的时候的底数都不变,为 \(c\),因此考虑对于每一个模数都预处理出来其对应的光速幂数组,这样时间复杂度就变为了 \(\mathcal O(n\sqrt{n\log p})\),块长取 \(\sqrt{\dfrac{n}{\log_2n}}\) 最优。

代码写分块的话细节很少,注意判断光速幂的过程中是否出现了指数 \(\ge p\) 的情况,方便计算的时候进行欧拉降幂。

#include<bits/stdc++.h>
using namespace std;
constexpr int _N = 5e4 + 5, _LEN = 250 + 5, _S = 1e4, _MS = _S + 5;
int n, m, p, c, ori[_N], a[_N], tim[_N];
map<int, int> phi, id;
int len, cnt, bl[_N], pos[_N], br[_N], sum[_N];
bool tag[_N];
int Getphi(int x) {
	int res = x;
	for (int i = 2; i * i <= x; ++i) {
		if (x % i) continue;
		res = res / i * (i - 1);
		while (!(x % i)) x /= i;
	}
	if (x > 1) res = res / x * (x - 1);
	return res;
}
int pw[_LEN][_MS][2], tP = 0;
bool flag[_LEN][_MS][2];
void Init(int P) {
	int x = id[P] = ++tP;
	pw[x][0][0] = pw[x][0][1] = 1;
	for (int i = 1; i <= _S; ++i) {
		flag[x][i][0] = flag[x][i - 1][0] || (1ll * pw[x][i - 1][0] * c >= P);
		pw[x][i][0] = 1ll * pw[x][i - 1][0] * c % P;
	}
	for (int i = 1; i <= _S; ++i) {
		flag[x][i][1] = flag[x][i - 1][1] || (1ll * pw[x][i - 1][1] * pw[x][i - 1][_S] >= P);
		pw[x][i][1] = 1ll * pw[x][i - 1][1] * pw[x][_S][0] % P;
	}
}
inline pair<int, bool> Lpow(int x, int P) {
	int i = id[P];
	int fir = 1ll * pw[i][x % _S][0] * pw[i][x / _S][1] % P;
	int sec = flag[i][x % _S][0] || flag[i][x / _S][1] || (1ll * pw[i][x % _S][0] * pw[i][x / _S][1] >= P);
	return {fir, sec};
}
inline pair<int, bool> GetAns(int x, int p, int tim) {
	if (!tim) return {x % p, x >= p};
	if (p == 1) return {0, 1};
	auto tmp = GetAns(x, phi[p], tim - 1);
	int b = tmp.first + tmp.second * phi[p];
	return Lpow(b, p);
}
void Change(int i) {
	(sum[pos[i]] += p - a[i]) %= p, ++tim[i];
	a[i] = GetAns(ori[i], p, tim[i]).first;
	(sum[pos[i]] += a[i]) %= p;
}
void Modify(int l, int r) {
	if (pos[l] == pos[r])
		for (int i = l; i <= r; ++i) Change(i);
	else {
		for (int i = l; i <= br[pos[l]]; ++i) Change(i);
		for (int i = pos[l] + 1; i < pos[r]; ++i) {
			if (tag[i]) continue; tag[i] = 1;
			for (int j = bl[i]; j <= br[i]; ++j) {
				int tmp = a[j]; Change(j);
				if (a[j] != tmp) tag[i] = 0;
			}
		}
		for (int i = bl[pos[r]]; i <= r; ++i) Change(i);
	}
}
int Query(int l, int r) {
	int res = 0;
	if (pos[l] == pos[r])
		for (int i = l; i <= r; ++i) (res += a[i]) %= p;
	else {
		for (int i = l; i <= br[pos[l]]; ++i) (res += a[i]) %= p;
		for (int i = pos[l] + 1; i < pos[r]; ++i) (res += sum[i]) %= p;
		for (int i = bl[pos[r]]; i <= r; ++i) (res += a[i]) %= p;
	}
	return res;
}
signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> n >> m >> p >> c;
	if (n == 1) len = 1;
	else len = sqrt(n / log2(n));
	cnt = (n - 1) / len + 1;
	for (int i = p; i > 1; i = phi[i]) phi[i] = Getphi(i), Init(i);
	Init(1);
	for (int i = 1; i <= n; ++i) cin >> a[i], ori[i] = a[i];
	for (int i = 1; i <= cnt; ++i) {
		bl[i] = (i - 1) * len + 1;
		br[i] = min(n, i * len);
	}
	for (int i = 1; i <= cnt; ++i)
		for (int j = bl[i]; j <= br[i]; ++j)
			pos[j] = i, (sum[i] += a[j]) %= p;
	for (int i = 1, opt, l, r; i <= m; ++i) {
		cin >> opt >> l >> r;
		if (opt) cout << Query(l, r) << '\n';
		else Modify(l, r);
	}
}

标签:le,六省,pw,测试点,13700558,int,样例,P3747,联考
From: https://www.cnblogs.com/hanx16msgr/p/17238007.html

相关文章

  • 省选联考 2021 A卷 图函数
    这个东西大概是可以转化成对于一个图,我们要支持加边,加边之后询问点对\((u,v)\)的对数,其中要求\(u<v\)并且\(u,v\)可以仅通过编号\(\geu\)的点双向到达。显然等价......
  • [省选联考 2021] 解题报告
    这两天(2023-3-12/13)开了一场省选VP,感触比较大,同时也有颇多要总结的地方,因此写下这篇博客。省选\(-20\)多天,我还在补一些没有仔细学的新算法,虽然感觉新学了很多东西,但是......
  • luogu P8294 [省选联考 2022] 最大权独立集问题
    题面传送门做了半个下午,写了大半个晚上,真的是dirtywork。首先一个点只会和父亲交换一次,并且交换了两边就相对独立了。因此我们考虑从这个方面入手dp。设\(f_{i,x,y}......
  • 【题解】P3747 [六省联考 2017] 相逢是问候
    思维难度作为一道省选题还是有待商榷,但是代码确实挺恶心的。记一下这种有关无穷层幂嵌套(无穷幂塔)的套路。思路扩展欧拉定理+线段树。首先看到不断嵌套幂并且模数较大......
  • [六省联考 2017] 组合数问题 题解
    题目描述组合数\(C_n^m\)表示的是从\(n\)个互不相同的物品中选出\(m\)个物品的方案数。举个例子,从\((1,2,3)\)三个物品中选择两个物品可以有\((1,2)\),\((1,......
  • P8292 [省选联考 2022] 卡牌
    我决定不整什么写过的题的集合了,写不过来。想到啥题好就写啥。这题是个很好的套路。考虑到值域不怎么大,想到根号分治。也就是小于根号的质数不超过\(14\)个,大于根号的......
  • [省选联考 2022] 填树 题解
    神奇dp。发现我看到dp大多数时候只会暴力。那我约等于退役了啊。题意:自己看。首先有一个显然的暴力。枚举一个最小值\(L\),然后区间就限定在了\([L,L+K]\)。那么普及......
  • 「解题报告」[省选联考 2021 A/B 卷] 图函数
    我不会最短路了?显然每对点能对答案造成的贡献是一个前缀,考虑求出每对点能造成贡献的最大时间。首先能发现,如果\(v>v'\),那么假如\(v\tov'\tou\),那么\(v'\tou\)......
  • 「解题报告」[省选联考 2021 A 卷] 矩阵游戏
    啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会了!啥都不会......
  • P3750 [六省联考 2017] 分手是祝愿
    \(\mathcalLink\)考虑建立异或方程组,则最终状态为该方程组的一个解,第\(i\)个方程形如\(\displaystyle\bigoplus_{i\midd}x_d=a_i\)。这些方程构成的向量线性无关,......