雖然說是一道裸題,但仍是讓小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。