题面链接
题意简述
求(prod_{i=A}^Bprod_{j=1}^i lgroup frac{i}{j} group ^{lfloor frac{i}{j} floor})
sol
我的做法是观察法,首先我们把(i)和(j^{-1})分开做,可以看到
(i)的是这样的。表格内是每个(i)和(j)的对应(i)的贡献
(1^1) | |||||
---|---|---|---|---|---|
(2^2) | (2^1) | ||||
(3^3) | (3^1) | (3^1) | |||
(4^4) | (4^2) | (4^1) | (4^1) | ||
(5^5) | (5^2) | (5^1) | (5^1) | (5^1) | |
(6^6) | (6^3) | (6^2) | (6^1) | (6^1) | (6^1) |
可以发现第(i)行我们只要快速求出指数就可以快速幂了。然后会发现一个神奇的性质,第(i)列每过(i)就会让指数加(1)。这样的话我们给(i,2i,3i,4i,5i...)加1,然后前缀和就行了。
要不还是再说清楚点吧。下面这个表是要加的指数。
1 | |||||||
---|---|---|---|---|---|---|---|
1 | 1 | ||||||
1 | 0 | 1 | |||||
1 | 1 | 0 | 1 | ||||
1 | 0 | 0 | 0 | 1 | |||
1 | 1 | 1 | 0 | 0 | 1 | ||
1 | 0 | 0 | 0 | 0 | 0 | 1 | |
1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 |
然后对每列做一遍前缀和。
1 | |||||||
---|---|---|---|---|---|---|---|
2 | 1 | ||||||
3 | 1 | 1 | |||||
4 | 2 | 1 | 1 | ||||
5 | 2 | 1 | 1 | 1 | |||
6 | 3 | 2 | 1 | 1 | 1 | ||
7 | 3 | 2 | 1 | 1 | 1 | 1 | |
8 | 4 | 2 | 2 | 1 | 1 | 1 | 1 |
然后就变回去了,这也许是差分的思想???具体实现不需要对每列开数组,丢到一起就OK了。
下面的1,2,3,4,5,6均指 他们的逆元
(1^1) | |||||
---|---|---|---|---|---|
(1^2) | (2^1) | ||||
(1^3) | (2^1) | (3^1) | |||
(1^4) | (2^2) | (3^1) | (4^1) | ||
(1^5) | (2^2) | (3^1) | (4^1) | (5^1) | |
(1^6) | (2^3) | (3^2) | (4^1) | (5^1) | (6^1) |
这是(j^{-1})的贡献。
然后和上面一样搞,但我们直接把这个数乘上去而不是加指数。
相信泥萌都懂了。那么我就贴个代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define gt getchar()
#define ll long long
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
inline int in()
{
int k=0;char ch=gt;
while(ch<'-')ch=gt;
while(ch>'-')k=k*10+ch-'0',ch=gt;
return k;
}
const int YL=19260817,N=2e6+5,M=1e6;
inline int ksm(int a,int k){int r=1;while(k){if(k&1)r=1ll*r*a%YL;a=1ll*a*a%YL,k>>=1;}return r;}
inline int MO(const int &a){return a>=YL?a-YL:a;}
int sum[N],sum_i[N],inv[N];
int main()
{
sum_i[0]=1;
for(int i=1;i<=M;++i)inv[i]=ksm(i,YL-2);
for(int i=1;i<=M;++i)
for(int j=i;j<=M;j+=i)++sum[j];
for(int i=1;i<=M;++i)sum[i]=(sum[i]+sum[i-1])%(YL-1);
for(int i=1;i<=M;++i)sum_i[i]=1ll*ksm(i,sum[i])*sum_i[i-1]%YL;
for(int i=1;i<=M;++i)sum[i]=1;
for(int i=1;i<=M;++i)
for(int j=i;j<=M;j+=i)sum[j]=1ll*sum[j]*inv[i]%YL;
for(int i=2;i<=M;++i)sum[i]=1ll*sum[i]*sum[i-1]%YL;
for(int i=2;i<=M;++i)sum[i]=1ll*sum[i]*sum[i-1]%YL;
for(int i=1;i<=M;++i)sum[i]=1ll*sum[i]*sum_i[i]%YL;
sum[0]=1;
int t=in();
while(t--)
{
int a=in(),b=in();
printf("%lld
",1ll*sum[b]*ksm(sum[a-1],YL-2)%YL);
}
return 0;
}