题目大意
CJY很喜欢吃蛋糕,于是YJC弄到了一块蛋糕,现在YJC决定和CJY分享蛋糕。
这块蛋糕上有n^2颗葡萄干,排成了一个n*n的点阵,每颗葡萄干互不相同且被编号为1~n^2。YJC决定沿着一条直线把蛋糕切成两份。YJC和CJY都很喜欢吃葡萄干,所以切出的两份蛋糕必须都包含至少一颗葡萄干。同时他们都不希望吃到不完整的葡萄干,所以切的时候不能经过任意一颗葡萄干。CJY喜欢1号葡萄干,所以他选择了包含1号葡萄干的那块蛋糕,而YJC则选择了另一块。
在吃蛋糕之前,CJY想知道有多少种切蛋糕的方案。两种方案是不同的当且仅当存在一颗葡萄干在一种方案中被分给了CJY,在另一种方案中被分给了YJC。CJY发现自己不会做这道题,所以他来向你请教。这个答案可能很大,你只需要告诉他答案mod p的结果就可以了。
筛
不会推结论
抄了std的式子
然后杜教筛啊
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=1000000+10;
ll sum[maxn][3],gg[maxn][3];
int phi[maxn],pri[maxn];
bool bz[maxn];
int i,j,k,l,t,n,m,top,mo,ans;
void prepare(){phi[1]=1;fo(i,2,maxn-10){if (!bz[i]) pri[++top]=i,phi[i]=i-1;fo(j,1,top){if ((ll)i*pri[j]>maxn-10) break;bz[i*pri[j]]=1;if (i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}phi[i*pri[j]]=phi[i]*(pri[j]-1);}}fo(i,1,maxn-10){sum[i][0]=(sum[i-1][0]+phi[i])%mo;sum[i][1]=(sum[i-1][1]+(ll)phi[i]*i%mo)%mo;sum[i][2]=(sum[i-1][2]+(ll)phi[i]*i%mo*i%mo)%mo;}
}
int getsum(int n,int k){int a,b,c;if (!k) return n;else if (k==1) return ((ll)n*(n+1)/2)%mo;else if (k==2){a=n;b=n+1;c=2*n+1;if (a%2==0) a/=2;else b/=2;if (a%3==0) a/=3;else if (b%3==0) b/=3;else c/=3;return (ll)a*b%mo*c%mo;}else{a=((ll)n*(n+1)/2)%mo;return (ll)a*a%mo;}
}
int calc(int n,int k){if (n<=maxn-10) return sum[n][k];if (gg[m/n][k]) return gg[m/n][k];int i=2,j,t,s0,s1,s2;s0=getsum(n,1);s1=getsum(n,2);s2=getsum(n,3);while (i<=n){j=n/(n/i);t=(getsum(j,0)-getsum(i-1,0))%mo;(s0-=(ll)t*calc(n/i,0)%mo)%=mo;t=(getsum(j,1)-getsum(i-1,1))%mo;(s1-=(ll)t*calc(n/i,1)%mo)%=mo;t=(getsum(j,2)-getsum(i-1,2))%mo;(s2-=(ll)t*calc(n/i,2)%mo)%=mo;i=j+1;}gg[m/n][0]=s0;gg[m/n][1]=s1;gg[m/n][2]=s2;return gg[m/n][k];
}
int main(){freopen("cake.in","r",stdin);freopen("cake.out","w",stdout);scanf("%d%d",&n,&mo);m=n;prepare();ans=(ll)n*n%mo*2%mo*calc(n,0)%mo;(ans-=(ll)3*n%mo*calc(n,1)%mo)%=mo;(ans+=calc(n,2))%=mo;ans=ans*2%mo;(ans+=mo)%=mo;printf("%d\n",ans);
}