沈阳网络赛 C Convex Hull (莫比乌斯反演+推公式+快速乘)*

题目链接:https://nanti.jisuanke.com/t/31444

#include<bits/stdc++.h>
#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define read(x,y) scanf("%d%d",&x,&y)

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ll long long
const int  maxn =1e5+5;
const int mod=1e9+7;
ll powmod(ll x,ll y) {ll t;for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod;return t;}
ll gcd(ll x,ll y)  {  return y==0?x:gcd(y,x%y); }
ll n,p;
/*
题目大意:计算个前缀和的前缀和。

如果只有一层前缀和,那么很好办,
还是用容斥(或者莫比乌斯)搞一搞。
这类型的题目,一定要对莫比乌斯系数前面的式子形式有感觉,
像这题,里面的求和函数只是x^2,很明显可以用
容斥,因为平方项是可以求和的,对平方和进行容斥即可。

但又加了一层前缀和这就要再分析下了,
画个图:
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
根据这个表,不难发现最终的结果可以
表示成5个1和4个2和3个3和。。。
即最终的式子就可以写成:
sigma gay(i)*(n+1-i)的形式。
这样的话还是和上面一样的解法,只是公式多套一层而已。

下面的一个难点就是模的范围,模的范围开到了11次方。。。。。
所以要用分块乘来搞一下,但还有个小问题,
模的数字不确定,如何对2和6的除数取模呢?
这里我也是网上学到的,先把模乘6或2带入运算,
最终再除以6或者2.
y/6%p=x%p;
y+6*t*p=6*x;
y=6*x%(6*p),就是对6*p同模。
这样分析就行了。
*/
///筛法筛莫比乌斯反演
int prim[maxn],tot=0;
int vis[maxn],miu[maxn];
void sieve()
{
    miu[1]=1;
    memset(vis,0,sizeof(vis));
    for(int i=2;i<maxn;i++)
    {
        if(vis[i]==0) prim[tot++]=i,miu[i]=-1;
        for(int j=0;j<tot;j++)
        {
            ll k=i*prim[j];
            if((ll)i*prim[j]>=maxn) break;
            vis[k]=1;
            if(i%prim[j]==0)
            {
                miu[i*prim[j]]=0;
                break;
            }
            miu[i*prim[j]]=-miu[i];
        }
    }
}
/*
inline ll fast_c(ll x,ll y)
{
    ll t=0;
    for(t=0;y;y>>=1,x=(x+x)%p)
        if(y&1) t=(t+x)%p;
    return t;
}
*/
const ll lb = (1LL << 20) - 1;
inline ll fast_c(ll x, ll y,ll md)
{
    ll a = x >> 20, b = x & lb;
    ll c = y >> 20, d = y & lb;
    return ( ( ( ( ( (a * c) << 20) + (a * d + b * c) ) % md) << 20) + b * d) % md;
}

inline ll getsum2(ll x)
{
    return fast_c(fast_c(x, x+1, 6*p), (2*x+1), 6*p) / 6%p;
    //return (__int128(N) * (N+1) * (2*N+1) / 6) % mod;
}
inline ll getsum3(ll x)
{
    ll tp=fast_c(x,x+1,p<<1)>>1;
    return fast_c(tp,tp,p);
}
/*
inline ll getsum2(ll x)
{
    ll tp1=x*(x+1)/2,tp2=2*x+1;
    if(tp1%3==0) tp1/=3;
    else tp2/=3;
    return fast_c(tp1,tp2,p);
}
inline ll getsum3(ll x)
{
    ll tmp=x*(x+1)/2%p;
    return fast_c(tmp,tmp,p);
}
*/
int main()
{
    sieve();
    while(~scanf("%lld%lld",&n,&p))
    {
        ll ans=0;
        for(int i=1;1LL*i*i<=n;i++)
        {
            if(miu[i])
            {
                ll t=1LL*i*i,t2=fast_c(t,t,p);
                ans=(ans+miu[i]*fast_c( fast_c(t2,n+1,p),getsum2(n/t),p ))%p;
                ans=(ans-miu[i]*fast_c( fast_c(t2,t,p),getsum3(n/t),p))%p;
            }
        }
        printf("%lld\n",(ans+p)%p);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37451344/article/details/82555399