洛谷P4902乘积

题面链接

洛谷

题意简述

\(\prod_{i=A}^B\prod_{j=1}^i \lgroup \frac{i}{j} \rgroup ^{\lfloor \frac{i}{j} \rfloor}\)

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\n",1ll*sum[b]*ksm(sum[a-1],YL-2)%YL);
    }
    return 0;
}
posted @ 2018-10-02 14:10  Cgod  阅读(258)  评论(0编辑  收藏  举报