题目描述
给定一个长度为 n 的数列 a,请回答 q 次询问,每次给定 l,r,请求出 ()mod p 的值,其中 p=1,145,141。
输入格式
第一行是两个整数,依次表示数列长度 n 和询问次数 q。
第二行有 n 个整数,第 i 个整数表示 ai。
接下来 q 行,每行两个整数 l,r,表示一次询问。
输出格式
为了避免大量数据输出导致超时,请输出一行一个整数表示所有询问的答案的按位异或和。
输入输出样例
输入 #1复制
5 3 1 2 3 4 5 2 3 3 4 2 4
输出 #1复制
18
说明/提示
样例 1 解释
三次询问的答案依次为 6,12,24,按位异或和为 18。
数据规模与约定
- 对于 30% 的数据,保证 n,q≤10^3。
- 对于60% 的数据,保证 n,q≤10^5。
对于全部的测试点,保证 1≤n,q≤10^6,1≤l≤r≤n,1≤ai<p。
提示
你可以在这里学习如何线性求逆元,请尽可能做到 O(1) 回答单次询问。
本题先求到n的前缀积,然后维护l-1的前缀积,r+1的后缀积,对l-1的前缀积,r+1的后求逆,
最后相乘再取模,欧克
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define endl '\n'
#define lowbit(x) ((x)&-(x))
#define pi 3.1415926535
const int mod=1145141;
typedef long long ll;
ll ans=0,n1,m1;
ll t=0,s1=0,s2=0,s3=0,s4=0,max1=0,max2=0,w,min1=100000000,sum=0,n,m,i,j,k,v,l,r;inline int read() {bool sym=0;int res=0;char ch=getchar();while(!isdigit(ch))sym |=(ch =='-'),ch=getchar();while(isdigit(ch)) res =(res<<3)+(res<<1)+(ch^48),ch=getchar();return sym ? -res : res;
}
void print(int x) {if(!x)return;print(x/10);putchar(x%10+'0');
}ll exgcd(ll a,ll b,ll &x,ll &y) {if(b==0) {x=1,y=0;return a;}ll d=exgcd(b,a%b,y,x);y-=a/b*x;return d;
}ll cc(ll a) {ll x,y;exgcd(a,mod,x,y);return (x%mod+mod)%mod;
}
ll a[1000086],b[1000869],c[1000860];
ll inv[1000860];
void invv(ll n){inv[0]=1;for(i=1;i<=n;i++){inv[i]=(mod-mod/a[i])*inv[mod%a[i]]%mod;}}
int main() {ll q;ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n>>q;for(i=1;i<=n;i++)cin>>a[i];invv(n);b[0]=1;c[n+1]=1;for(i=1;i<=n;i++){b[i]=b[i-1]*a[i]%mod;}for(i=n;i>=1;i--){c[i]=c[i+1]*a[i]%mod;}s1=b[n];// 前缀积 ans=0; while(q--){cin>>l>>r;s2=cc(b[l-1]);s3=cc(c[r+1]);//cout<<s2<<" "<<s3<<endl;// cout<<s1*s2*s3%mod<<endl;ans^=s1*s2*s3%mod;}cout<<ans;return 0;
}//mio lover