洛谷 - B3645

Description

给定一个长度为 n 的数列 𝑎,请回答 𝑞 次询问,每次给定 𝑙,𝑟请求出 的值,其中 𝑝=1,145,141。

Input

第一行是两个整数,依次表示数列长度 𝑛 和询问次数 q。
第二行有 n 个整数,第 𝑖个整数表示 ai​。
接下来 𝑞行,每行两个整数 𝑙,𝑟表示一次询问。

Output

为了避免大量数据输出导致超时,请输出一行一个整数表示所有询问的答案的按位异或和。

Sample 1

InputcopyOutputcopy
5 3
1 2 3 4 5
2 3
3 4
2 4
18

这道题感觉你弄会两个点就可以写出来,第一个点就是求逆元(用快速幂,或者说费马小定理,因为费马小定理的模板基本上就是快速幂)第二个点是用前缀积(因为题目中是一段区间相乘的结果),对了还需要注意题目最后说的按位异或和,如果我前面说的两个知识点你都会,那么恭喜你,这道题你绝对会写,不会的话建议你把这两个知识点学一学。废话不多说,上代码

这里我说一下为什么要用逆元来算,就比如一个a数组,a[1]=1,a[2]=2,a[3]=3,那么前缀积sum数组,sum[1]=1,sum[2]=2,sum[3]=6,求二到三之间的数,你直接用(sum[3]/sum[1])%p就行了,结果为6,等价于a[2]*a[3]=6,而这里(sum[3]/sum[1])%p就可以运用到逆元,直接sum[3]*(sum[1]^p-2)%p,将除法转化成乘法,再用快速幂写,很快

我逆元只懂得这些皮毛,你们可以看看其他大佬的关于逆元的文章

#include"iostream"
#include<cstdio>
using namespace std;
const int N=1e6+10;
int p=1145141;
long long a[N],sum[N];
long long qm(long long base,long long power)//这个是快速幂的模版!!!,不会有太大的改变
{
	long long result=1;
	while(power!=0)
	{
		if(power%2!=0)
			result=base*result%p;
		power/=2;
		base=base*base%p;
	}
	return result;
}
int main()
{
	int n,q;
	scanf("%d %d",&n,&q);
	sum[0]=1;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		sum[i]=(sum[i-1]*a[i])%p;//数组sum是数组a的前缀积,因为数可能会很大,所以要模p
	}	
	int s=0;
	while(q--)
	{
		int x,y;
		scanf("%d %d",&x,&y);
		s=s^sum[y]*qm(sum[x-1],p-2)%p;逆元(用快速幂实现的)
	}
	printf("%d",s);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值