当前位置: 代码迷 >> 综合 >> 沈阳网络赛 C Convex Hull (莫比乌斯反演+推公式+快速乘)*
  详细解决方案

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

热度:24   发布时间:2023-11-15 16:03:06.0

题目链接: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;
}