虽然说是一道裸题,但仍是让小C学到了一点姿式的。算法
给定一个长度为n的数组w,模数m和询问次数q,每次询问给定l,r,求:数组
对m取模的值。spa
第一行两个整数n,m,表示数组长度和模数。
接下来一行n个数,表示w数组。
接下来一行一个整数q,表示询问次数。
接下来q行,每行两个整数l,r,表示一次询问。3d
对于每次询问,输出一行一个整数表示答案。code
6 1000000000
1 2 2 3 3 3
8
1 1
1 6
2 2
2 3
2 4
4 4
4 5
4 6blog
1
1
2
4
256
3
27
597484987递归
1 ≤ n ≤ 105,1 ≤ m ≤ 109,1 ≤ wi ≤ 109,1 ≤ q ≤ 105,1 ≤ l ≤ r ≤ n。
ip
看到这么清奇的式子,你大概会第一时间想到降幂大法吧?get
先说说扩展欧拉定理,对于任意正整数a,b,p:string
因此假设堆叠的幂次足够大,那么式子就能够转化为:
已知p通过至多2log次phi就会变成1。
因此递归求解,至多走到2log层模数就会变成1,因此返回0就行。
因此这道题就很是显然了,首先预处理出m的全部phi,对于每一个询问,从l开始直接递归暴力,直到模数为1时返回。
还有一个问题,在求a^b%p的时候,怎么比较b和phi(p)的大小呢?
一种思路就是暴力计算a的后log项的值,注意还要特判1的状况,但这样写起来确实麻烦。
固然,有一种很是精妙的取模写法:
int modulo(ll x,int mod) {return x<mod?x:x%mod+mod;}
这是在作什么呢?这就是在比较b和phi(p)的大小,若是b<phi(p),返回b;不然返回b%phi(p)+phi(p)。
而后原式就变成了这样:
这样作看上去漏洞百出,可能的状况是,本来咱们要计算,其中
大等于
。
然而咱们计算,将
取模后,却发现
小于
了。
是否有这种可能呢?
其实就至关于判断是否有可能成立,咱们能够发现,当a>2时式子是不可能成立的。
因此咱们来看一看 是否有可能成立。
有可能。
当且仅当p=6时,不等式成立。
然而6有什么特殊的性质呢?
咱们发现phi(x)=6只有两个解:x=7或x=9。
当x=7时,,因此
少一个
对于答案是没有影响的。
当x=9时,若gcd(a,9)=1,则,影响同上;
若gcd(a,9)≠1,由于,因此
,
又由于必定有,因此必定有
,
因此必定有,因此少一个
对于答案是没有影响的。
因此综上,咱们就证实了该算法的正确性。
时间复杂度。
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long #define MN 100005 using namespace std; int a[MN],mod[MN]; int n,p; bool fg; inline int read() { int n=0,f=1; char c=getchar(); while (c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();} while (c>='0' && c<='9') {n=n*10+c-'0'; c=getchar();} return n*f; } inline int pro(ll x,int md) {return x<md?x:x%md+md;} inline int mi(int x,int y,int md) { register int z=1; for (;y;x=pro(1LL*x*x,md),y>>=1) if (y&1) z=pro(1LL*z*x,md); return z; } int dfs(int x,int y,int lim) { if (x==lim) return a[x]>=mod[y]?a[x]%mod[y]+mod[y]:a[x]; if (mod[y]==1) return 1; return mi(a[x],dfs(x+1,y+1,lim),mod[y]); } int main() { register int i,j,x,y; n=read(); mod[1]=read(); for (i=1;mod[i]>1;++i) { mod[i+1]=x=mod[i]; for (j=2;j*j<=x;++j) { for (fg=0;x%j==0;x/=j,fg=true); if (fg) mod[i+1]=1LL*mod[i+1]*(j-1)/j; } if (x>1) mod[i+1]=1LL*mod[i+1]*(x-1)/x; } for (i=1;i<=n;++i) a[i]=read(); for (p=read();p;--p) { x=read(); y=read(); printf("%d\n",dfs(x,1,y)%mod[1]); } }
打Codeforces的时候正纳闷这种状况该怎么处理,却发现大佬们清一色都是这么写的。
小C以为本身的证实蠢得不行啊……
若是读者有更直观的证实该算法的正确性的方法请务必告诉小C。