【反演复习计划】【bzoj4407】于神之怒加强版

#include<bits/stdc++.h>
#define N 5000010
#define yql 1000000007
using namespace std;
typedef long long ll;
int T,k,n[2010],m[2010],maxn,vis[N],prime[N];
int mu[N],cnt=0,fac[N];
ll f[N],s[N];
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
inline ll fpow(ll x,ll p){
    x%=yql;ll ans=1;
    for(;p;p>>=1,x=x*x%yql)if(p&1)ans*=x,ans%=yql;
    return (ans+yql)%yql;
}
void calcmu(){
    cnt=0;mu[1]=1;s[1]=1;memset(vis,1,sizeof(vis));
    for(int i=2;i<=maxn;i++){
        if(vis[i]){prime[++cnt]=i;fac[i]=i;mu[i]=-1;f[i]=fpow(i,k);s[i]=f[i]-1;}
        for(int j=1;j<=cnt;j++){
            int p=prime[j],t=i*p;if(t>maxn)break;
            vis[t]=0;
            if(i%p==0){
                mu[t]=0;fac[t]=fac[i]*p;
                s[t]=1LL*s[i]*f[prime[j]]%yql;
                break;
            }
            mu[t]=-mu[i];s[t]=1LL*s[i]*s[p]%yql;
        }
    }
    for(int i=1;i<=maxn;i++)mu[i]+=mu[i-1],s[i]+=s[i-1],s[i]%=yql;
}
int main(){
    T=read();k=read();
    for(int i=1;i<=T;i++){
        n[i]=read(),m[i]=read();
        maxn=max(maxn,max(n[i],m[i]));
    }
    calcmu();
    for(int i=1;i<=T;i++){
        int nn=n[i],mm=m[i];if(nn>mm)swap(nn,mm);
        ll ans=0;
        for(int i=1,j=1;i<=nn;i=j+1){
            j=min(mm/(mm/i),nn/(nn/i));
            ans+=(s[j]-s[i-1]+yql)%yql*(nn/i)%yql*(mm/i)%yql;ans%=yql;
        }
        printf("%lld\n",ans);
    }
}

试了下maxn操作,结果还是BZOJ倒数TAT

感觉式子化得没问题啊?

posted @ 2017-05-24 12:37  zcysky  阅读(211)  评论(0编辑  收藏  举报