ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷 P4588 [TJOI2018]数学计算

2022-06-26 22:01:21  阅读:107  来源: 互联网

标签:le 洛谷 int long include 操作 P4588 TJOI2018 define


传送门

Description

现在有一个数 \(x\),初始值为 \(1\)。有 \(Q\) 次操作,操作有两种:

\(1\) \(m\):将 \(x\) 变为 \(x \times m\),并输出 \(x \bmod M\)

\(2\) \(pos\):将 \(x\) 变为 \(x\) 除以第 \(pos\) 次操作所乘的数(保证第 \(pos\) 次操作一定为类型 \(1\),对于每一个类型 \(1\) 的操作至多会被除一次),并输出 \(x \bmod M\)。

每个测试点共有 \(T\) 组输入。

对于 \(20\%\) 的数据,\(1 \le Q \le 500\)。

对于 \(100\%\) 的数据,\(1 \le Q \le 10^5\),\(T \le 5, M \le 10^9\),\(0 < m \leq 10^9\)。

Solution 0 \(TLE\) or \(WA\)

扫一眼题目,这题似乎能用模拟解决。

然而我们发现,若使用高精度乘法,时间必然会不够,直接吃一个 TLE。

同时,由于出现了除法,所以在取模时应当想到逆元,但是 \(M\) 并不一定为质数,逆元也不可做。

Solution 1

注意看题目里我加粗的那行字,题中保证了每次乘操作在后面的除操作中至多只用一次。

想想后面的除操作,是不是就相当于将前面的乘操作抵消掉呢?(抵消掉,意思就是把乘操作的值变回 \(1\))

把“时间”(操作次数) \(i\) 抽象成一个个初始为 \(1\) 点,乘操作就是把该“时间” \(i\) 的值修改为乘上的值,除操作就是把这个位置上的值变为 \(1\),则每次询问的答案就是从 \(1\) 位置到 \(i\) 所有数之积对 \(M\) 取模。

可以看出,这就是单点修改和区间查询,自然能够想到使用树状数组或线段树维护。

Code

最近在学线段树,就拿线段树来写了~

注意一开始整棵线段树要全赋为 \(1\),注意开 long long。

// by youyou2007 in 2022.
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#define int long long
#define REP(i, x, y) for(int i = x; i < y; i++)
#define rep(i, x, y) for(int i = x; i <= y; i++)
#define PER(i, x, y) for(int i = x; i > y; i--)
#define per(i, x, y) for(int i = x; i >= y; i--)
#define lc (k << 1)
#define rc (k << 1 | 1)
using namespace std;
const int N = 1E5 + 5;
int MOD;
int T;
int q;
int m[N];
int f[N * 4]; 
void pushup(int k)
{
	f[k] = (f[lc] * f[rc]) % MOD; 
}
void modify(int l, int r, int q, int k, int d, int opt)//单点修改
{
	if(l == r && l == q)
	{
		if(opt == 1)
		{
			f[k] = d;
		}
		else
		{
			f[k] = 1;
		}
		return;
	}
	int mid = (l + r) / 2;
	if(q <= mid)
	{
		modify(l, mid, q, lc, d, opt);
	}
	else
	{
		modify(mid + 1, r, q, rc, d, opt);
	}
	pushup(k);
}
signed main()
{
	scanf("%lld", &T);
	while(T--)
	{
		scanf("%lld%lld", &q, &MOD);
		rep(i, 1, q * 4 + 5)//整棵线段树都要赋 1
		{
			f[i] = 1; 
		}
		rep(i, 1, q)
		{
			int opt, m;
			scanf("%lld%lld", &opt, &m);
			if(opt == 1)
			{
				modify(1, q, i, 1, m, 1);//如果是乘操作,就在位置 i 上面修改成 m
				printf("%lld\n", f[1] % MOD);//这里进行了一个简化,因为 i 位置之后都是 1,对答案无影响,所以可以直接输出整课线段树的积,即 f[1] 的值	
			}
			else
			{

				modify(1, q, m, 1, 1, 2);//如果是除操作,就在位置 m(pos)上面修改成 1
				printf("%lld\n", f[1] % MOD);
			}
		}
	}
	return 0;
}

标签:le,洛谷,int,long,include,操作,P4588,TJOI2018,define
来源: https://www.cnblogs.com/pjxpjx/p/16414016.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有