2020 Jiangsu Collegiate Programming Contest-A.Array

11 篇文章 0 订阅
7 篇文章 0 订阅

Array

题目描述

Yukikaze received an array (a1,a2,⋯an)as a gift. She decided to play with it. The game consists of q turns. In each turn, she will perform some kind of operation (listed below) on all elements in a subarray of a.
在这里插入图片描述
In this problem, we define that 00=1.
Since the result of operations of the last two kinds may be large, you only have to find it modulo a small integer p.

输入

Input
The first line of the input contains two integers n,p (1≤n≤105,2≤p≤30), denoting the number of elements in the array a and the modulus for the operations of type 4 and 5.
The next line contains n integers a1,a2,⋯,an (0≤ai≤109), denoting the initial elements in the array a.
The third line contains one integer q (1≤q≤105), denoting the number of operations to be performed.
Each of the following q lines contains 4 integers t,l,r,k (1≤t≤5,1≤l≤r≤n,0≤k≤109) represents an operation of kind t. Note that if t=5, it’s guaranteed that k=0.

输出

For each operation of type 4 or 5, output the result modulo p as an integer in a single line.

Sample Input

5 29
5 2 4 1 3
9
4 2 4 1
1 1 3 2
2 2 4 3
3 3 5 2
5 3 3 0
4 1 5 2
2 3 5 0
3 2 4 0
4 3 4 1

Sample Output

7
5
3
2

解题思路

本题很显然是个线段树。先说整体思路,然后我们再细细研究

1.我们宏观上需要实现的是查询和与积,但是这里的每个元素都是相互独立的。那么我们完全可以先统计他们的个数,然后再计算。因此我们计算用到了以下两个代码

ans += EularPow(i, k, mod) * cnt[i];
ans %= mod;
ans *= EularPow(i, cnt[i], mod);
ans %= mod;

这里应该一眼就能看出来含义
2.我们需要设计30棵树来维护,因为他们的每个值都在0-30之间,那么,我们维护每棵树的元素个数就可以了。
3.我们需要设计懒惰标记。我们这里懒惰标记表示当前这个懒惰标记对应的值,应该转换成什么值。这里拿纸笔画一画自然就明了了。为了明确,还是举个例子。
比如当前我的懒惰标记是1 2 3 4 5,但是父亲的懒惰标记是 1 8 27 64 125,这样我们可以理解,所有的1号都变成了父亲对应值1,2对应8,3对应27等等
当我们计算的时候,我们当前的懒惰标记下传就会改变当前的懒惰标记,以实现值的修改。
4.值的修改就是从某棵树上删除,然后另一棵树上增加
5.查询,把遍历的数量结果统计出来
6.计算pow时候需要用到欧拉降幂。亲测,不用欧拉降幂会TLE,这里就是一步优化。
7.输入输出挂会被卡
8.用longlong增大了运算量,会被卡

接下来会放出欧拉降幂的代码

a b ≡ { a b % φ ( p ) g c d ( a , p ) = 1 a b g c d ( a , p ) ≠ 1 , b < φ ( p ) a b % φ ( p ) + φ ( p ) g c d ( a , p ) ≠ 1 , b ≥ φ ( p ) ( m o d    p ) a^{b}\equiv \left\{\begin{matrix} a^{b\%\varphi (p)} &gcd(a,p)=1 \\ a^{b}&gcd(a,p)\neq 1,b<\varphi(p) \\ a^{b\%\varphi (p)+\varphi (p)}&gcd(a,p)\neq 1,b\ge \varphi(p) \end{matrix}\right.\quad (mod\; p) abab%φ(p)abab%φ(p)+φ(p)gcd(a,p)=1gcd(a,p)=1,b<φ(p)gcd(a,p)=1,bφ(p)(modp)

ll EularPow(ll a, ll b, ll mod) {
	ll ans = 1;
	if (gcd(a, mod) == 1)b = b % phi;
	else if (b >= phi)b = b % phi + phi;
	while (b > 0) {
		if (b & 1) ans = ans * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}

至于phi的值需要用欧拉函数来解,这里一并放出

ll eular(ll n)
{
	ll ans = n;
	for (ll i = 2; i * i <= n; i++)
		if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0)n /= i; }
	if (n > 1)ans = ans / n * (n - 1); return ans;
}

思路分析完毕

Accept Code

#include<unordered_map>
#include<algorithm>
#include<iostream>
#include<string.h>
#include <iomanip>
#include<stdio.h>
#include<vector>
#include<string>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll ll_inf = 9223372036854775807;
const int int_inf = 2147483647;
const short short_inf = 32767;
const ll less_inf = 0x3f3f3f3f;
const char char_inf = 127;
#pragma GCC optimize(2)
#pragma warning(disable:6031)
#define accelerate cin.tie(NULL);cout.tie(NULL);ios::sync_with_stdio(false)
#define PI 3.141592653589793
#define EPS 1.0e-8
ll gcd(ll a, ll b) {
	return b ? gcd(b, a % b) : a;
}
ll lcm(ll a, ll b) {
	return a / gcd(a, b) * b;
}
inline ll read() {
	ll c = getchar(), Nig = 1, x = 0;
	while (!isdigit(c) && c != '-')c = getchar();
	if (c == '-')Nig = -1, c = getchar();
	while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
	return Nig * x;
}
inline void out(ll a) {
	if (a < 0)putchar('-'), a = -a;
	if (a > 9)out(a / 10);
	putchar(a % 10 + '0');
}
ll qpow(ll x, ll n, ll mod) {
	ll res = 1;
	while (n > 0) {
		if (n & 1)res = (res * x) % mod;
		x = (x * x) % mod;
		n >>= 1;
	}
	return res;
}
#define read read()
const int N = 100005;
int mod;
int tree[N << 2][31];
int lazy[N << 2][31];
int temp[31];
int cnt[31];
int tot = 0;
vector<int>save;
int phi;
ll eular(ll n)
{
	ll ans = n;
	for (ll i = 2; i * i <= n; i++)
		if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0)n /= i; }
	if (n > 1)ans = ans / n * (n - 1); return ans;
}

ll EularPow(ll a, ll b, ll mod) {
	ll ans = 1;
	if (gcd(a, mod) == 1)b = b % phi;
	else if (b >= phi)b = b % phi + phi;
	while (b > 0) {
		if (b & 1) ans = ans * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}

void push_up(int rt)
{
	for (int i = 0; i < mod; i++)
		tree[rt][i] = tree[rt << 1][i] + tree[rt << 1 | 1][i];
}
void push_down(int rt)
{
	for (int i = 0; i < mod; i++)
	{
		temp[i] = tree[rt << 1][i];
		tree[rt << 1][i] = 0;
	}
	for (int i = 0; i < mod; i++)
		tree[rt << 1][lazy[rt][i]] += temp[i];
	for (int i = 0; i < mod; i++)
	{
		temp[i] = tree[rt << 1 | 1][i];
		tree[rt << 1 | 1][i] = 0;
	}
	for (int i = 0; i < mod; i++)
		tree[rt << 1 | 1][lazy[rt][i]] += temp[i];
	for (int i = 0; i < mod; i++)
	{
		lazy[rt << 1][i] = lazy[rt][lazy[rt << 1][i]];
		lazy[rt << 1 | 1][i] = lazy[rt][lazy[rt << 1 | 1][i]];
	}
	for (int i = 0; i < mod; i++)lazy[rt][i] = i;
}
void creat(int l, int r, int rt)
{
	if (l == r)
	{
		tree[rt][save[tot++] % mod]++;
		return;
	}
	for (int i = 0; i < mod; i++)
		lazy[rt][i] = i;
	int mid = l + r >> 1;
	creat(l, mid, rt << 1);
	creat(mid + 1, r, rt << 1 | 1);
	push_up(rt);
}
ll change(ll num, ll val, ll ord)
{
	switch (ord)
	{
	case 1:return (num + val) % mod;
	case 2:return (num * val) % mod;
	default:return EularPow(num, val, mod);
	}
}
void update(int ord, int k, int L, int R, int l, int r, int rt)
{
	if (L <= l && r <= R)
	{
		for (int i = 0; i < mod; i++)
		{
			temp[i] = tree[rt][i];
			tree[rt][i] = 0;
		}
		for (int i = 0; i < mod; i++)
		{
			int num = change(i, k, ord);
			lazy[rt][i] = change(lazy[rt][i], k, ord);
			tree[rt][num] += temp[i];
		}
		return;
	}
	push_down(rt);
	int mid = l + r >> 1;
	if (L <= mid)update(ord, k, L, R, l, mid, rt << 1);
	if (R > mid)update(ord, k, L, R, mid + 1, r, rt << 1 | 1);
	push_up(rt);
}
void query(int L, int R, int l, int r, int rt)
{
	if (L <= l && r <= R)
	{
		for (int i = 0; i < mod; i++)
			cnt[i] += tree[rt][i];
		return;
	}
	push_down(rt);
	int mid = l + r >> 1;
	if (L <= mid)query(L, R, l, mid, rt << 1);
	if (R > mid)query(L, R, mid + 1, r, rt << 1 | 1);
}
int main()
{
	int n;
	scanf("%d%d", &n, &mod);
	phi = eular(mod);
	for (int i = 0; i < n; i++)
	{
		int t;
		scanf("%d", &t);
		save.push_back(t);
	}
	creat(1, n, 1);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int ord, l, r, k;
		scanf("%d%d%d%d", &ord, &l, &r, &k);
		if (ord <= 3)
			update(ord, k, l, r, 1, n, 1);
		else if (ord == 4)
		{
			memset(cnt, 0, sizeof(cnt));
			query(l, r, 1, n, 1);
			int ans = 0;
			for (int i = 0; i < mod; i++)
			{
				ans += EularPow(i, k, mod) * cnt[i];
				ans %= mod;
			}
			printf("%d\n", ans);
		}
		else
		{
			memset(cnt, 0, sizeof(cnt));
			query(l, r, 1, n, 1);
			int ans = 1;
			for (int i = 0; i < mod; i++)
			{
				ans *= EularPow(i, cnt[i], mod);
				ans %= mod;
			}
			printf("%d\n", ans);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Round moon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值