[WC2014]时空穿梭

声明:我还没有退役,只是Typora太好用,懒得写博客了而已,比较好的题还是会放上来

鼓起勇气写了一个冬令营

有了[BZOJ3518] 点组计数的基础

显然答案为
\[ \sum_{x_1=1}^{m_1}\sum_{x_2=1}^{m_2}...\sum_{x_n=1}^{m_n}(^{gcd(x_1,...x_n)-1}_{c-2})*\prod_{i=1}^{n}(m_i-x_i) \]
然而这次\(gcd\)函数在组合数里面

并不能用\(\varphi\)反演

所以这次用\(\mu\)反演
\[ \sum_{x_1=1}^{m_1}\sum_{x_2=1}^{m_2}...\sum_{x_n=1}^{m_n}(^{gcd(x_1,...x_n)-1}_{c-2})*\prod_{i=1}^{n}{(m_i-x_i)} \\=\sum_{d=1}^{m}{(^{d-1}_{c-2})}\sum_{x_1=1}^{\lfloor \frac{m_1}{d}\rfloor}\sum_{x_2=1}^{\lfloor \frac{m_2}{d}\rfloor}...\sum_{x_n=1}^{\lfloor \frac{m_n}{d}\rfloor}{[gcd(x_1,...x_n)=1]*\prod_{i=1}^{n}{(m_i-d*x_i)}} \\=\sum_{d=1}^{m}{(^{d-1}_{c-2})}\sum_{x_1=1}^{\lfloor \frac{m_1}{d}\rfloor}\sum_{x_2=1}^{\lfloor \frac{m_2}{d}\rfloor}...\sum_{x_n=1}^{\lfloor \frac{m_n}{d}\rfloor}{\sum_{t|gcd(x_1,...x_n)}{\mu(t)}\prod_{i=1}^{n}{(m_i-d*x_i)}} \\=\sum_{d=1}^{m}{(^{d-1}_{c-2})}\sum_{t=1}^{\lfloor \frac{m}{d}\rfloor}{\mu(t)}\sum_{x_1=1}^{\lfloor \frac{m_1}{dt}\rfloor}\sum_{x_2=1}^{\lfloor \frac{m_2}{dt}\rfloor}...\sum_{x_n=1}^{\lfloor \frac{m_n}{dt}\rfloor}\prod_{i=1}^{n}{(m_i-d*t*x_i)} \\=\sum_{d=1}^{m}{(^{d-1}_{c-2})}\sum_{t=1}^{\lfloor \frac{m}{d}\rfloor}{\mu(t)}\sum_{x_1=1}^{\lfloor \frac{m_1}{dt}\rfloor}{{(m_1-d*t*x_1)}}\sum_{x_2=1}^{\lfloor \frac{m_2}{dt}\rfloor}{(m_2-d*t*x_2)}...\sum_{x_n=1}^{\lfloor \frac{m_n}{dt}\rfloor}{(m_n-d*t*x_n)} \\=\sum_{d=1}^{m}{(^{d-1}_{c-2})}\sum_{t=1}^{\lfloor \frac{m}{d}\rfloor}{\mu(t)}\prod_{i=1}^{n}{(m_i*\lfloor \frac{m_i}{dt}\rfloor-d*t*\frac{\lfloor \frac{m_1}{dt}\rfloor*(\lfloor \frac{m_1}{dt}\rfloor+1)}{2})} \\=\sum_{d=1}^{m}\sum_{d'|d}{(^{d'-1}_{c-2})*\mu(\frac{d}{d'})*\prod_{i=1}^{n}{(m_i*\lfloor \frac{m_i}{d}\rfloor-d*\frac{\lfloor \frac{m_1}{d}\rfloor*(\lfloor \frac{m_1}{d}\rfloor+1)}{2})}} \]
至此

复杂度为\(O(Tmn)\)算下来大概\(1e8\)

然而还可以再优化


\[ F(d)=\prod_{i=1}^{n}{(m_i*\lfloor\frac{m_i}{d}\rfloor-d*\frac{\lfloor\frac{m_1}{d}\rfloor*(\lfloor \frac{m_1}{d}\rfloor+1)}{2})} \]
显然\(F(d)\)是关于\(d\)的一个\(n\)次函数

可以\(O(n^2)\)计算其所有系数

设这些系数是\(a_0,a_1,...a_n\)

原式即可变为
\[ \sum_{d=1}^{m}\sum_{d'|d}{(^{d'-1}_{c-2})*\mu(\frac{d}{d'})*\sum_{i=0}^{n}{a_i*d^i}} \\=\sum_{d=1}^{m}\sum_{i=0}^{n}{a_i*(d^i*\sum_{d'|d}{(^{d'-1}_{c-2})*\mu(\frac{d}{d'}}))} \]
后面那部分可以在\(O(mnc)\)内预处理出前缀和

每次询问\(O(n^3\sqrt{m})\)(处理\(a\)\(n^2\),需要算\(n\sqrt{m}\)次,因为\(d\)\(n\sqrt{m}\)种取值)

代码如下

#include<bits/stdc++.h>

using namespace std;

#define gc c=getchar()
#define r(x) read(x)
#define ll long long 

template<typename T>
inline void read(T&x){
    x=0;T k=1;char gc;
    while(!isdigit(c)){if(c=='-')k=-1;gc;}
    while(isdigit(c)){x=x*10+c-'0';gc;}x*=k;
}

const int p=10007;
const int N=1e5+7;
const int S=21;
const int W=12;

inline int add(int a,int b){
    a+=b;
    if(a>=p)a-=p;
    return a;
}

int C[N][S],P[N][W],f[N][S],sum[N][S][W];

int tot;
int pri[N],mu[N];
bool mark[N];

inline void pre(int n){
    mu[1]=1;
    for(int i=2;i<=n;++i){
        if(!mark[i])pri[++tot]=i,mu[i]=-1;
        for(int j=1,tmp;j<=tot&&(tmp=i*pri[j])<=n;++j){
            mark[tmp]=1;
            if(i%pri[j]==0){
                mu[tmp]=0;
                break;
            }
            mu[tmp]=-mu[i];
        }
    }
    C[0][0]=1;
    for(int i=1;i<=n;++i){
        C[i][0]=1;
        for(int j=1;j<S;++j){
            C[i][j]=add(C[i-1][j-1],C[i-1][j]);
        }
    }
    for(int i=0;i<=n;++i){
        P[i][0]=1;
        for(int j=1;j<W;++j){
            P[i][j]=P[i][j-1]*i%p;
        }
    }
    for(int i=1;i<=n;++i){
        for(int j=1;i*j<=n;++j){
            for(int k=2;k<S;++k){
                f[i*j][k]=add(f[i*j][k],add(p,C[i-1][k-2]*mu[j]));
            }
        }
    }
    for(int i=1;i<=n;++i){
        for(int j=2;j<S;++j){
            for(int k=0;k<W;++k){
                sum[i][j][k]=add(sum[i][j][k],add(sum[i-1][j][k],f[i][j]*P[i][k]%p));
            }
        }
    }
}

int a[W];

struct query{
    int n,c,M;
    int m[W];

    inline void init(int d){
        memset(a,0,sizeof(a));
        a[0]=1;
        for(int i=1;i<=n;++i){
            ll t=m[i]/d;
            ll x=m[i]*t%p;
            ll y=p-(t*(t+1)>>1)%p;
            for(int j=n;j;--j){
                a[j]=(a[j]*x+a[j-1]*y)%p;
            }
            a[0]=a[0]*x%p;
        }
    }

    inline void solve(){
        ll ans=0;
        for(int i=1,nex;i<=M;i=nex+1){
            nex=M;
            for(int j=1;j<=n;++j){
                nex=min(nex,m[j]/(m[j]/i));
            }
            init(i);
            for(int j=0;j<=n;++j){
                ans+=a[j]*add(sum[nex][c][j],p-sum[i-1][c][j]);
            }
        }
        printf("%lld\n",ans%p);
    }

}Q[1005];

int main(){
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    int T,MaxM=0;r(T);
    for(int i=1;i<=T;++i){
        r(Q[i].n),r(Q[i].c);Q[i].M=N;
        for(int j=1;j<=Q[i].n;++j){
            r(Q[i].m[j]);
            MaxM=max(MaxM,Q[i].m[j]);
            Q[i].M=min(Q[i].M,Q[i].m[j]);
        }
    }
    pre(MaxM);
    for(int i=1;i<=T;++i)Q[i].solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yicongli/p/10165489.html