P5221 Product 题解
式子推过头了/kk,虽然这样也能做。
其实直接筛 \(\varphi\) 就好了啊
然后一层一层代回去就好了
const int N=1000005;
const int mod=104857601;
int n,fz=1,fm=1,ans;
int pri[N],cnt,phi[N];
bool vis[N];
int qpow(int n,int k){
int res=1;
while(k){
if(k&1)res=1ll*res*n%mod;
n=1ll*n*n%mod,k>>=1;
}
return res;
}
void qmod(int&x,int mod){
x+=x>>31&mod,x-=mod,x+=x>>31&mod;
}
void Sieve(const int&N) {
phi[1]=1;
for (int i=2;i<=N;++i){
if(!vis[i])pri[++cnt]=i,phi[i]=i-1;
for (int j=1;j<=cnt&&i*pri[j]<=N;++j) {
vis[i*pri[j]]=1;
if (i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}
phi[i*pri[j]]=phi[i]*phi[pri[j]];
}
}
for(int i=1;i<=N;++i)qmod(phi[i]+=phi[i-1],mod-1);
}
signed main(){
n=read();
// n=1000000;
Sieve(n);
for(int i=1;i<=n;++i)fz=1ll*fz*qpow(i,2*n)%mod;
for(int i=1;i<=n;++i)fm=1ll*fm*qpow(qpow(i,phi[n/i]*2-1),mod-2)%mod;
ans=1ll*fz*fm%mod*fm%mod,printf("%d\n",ans);
return 0;
}
于是发现您只有 \(0\) 分,大片MLE
???
\(O(n)\) 的空间怎么MLE的
看一眼空间:\(7.81MB\) 怎么两位小数啊
开始算空间。
\(2e6\) 个\(int\) 与 \(1e6\) 个 \(bool\):\((2e6*4+1e6)/1024/1024=8.58306884765625MB\)
???????????????
该咋办啊
筛完发现质数只有 \(78498\) 个,开到 \(78500\) ,再算。
\((1078500*4+1000000)/1024/1024=5.0678253173828125\)
可以过了。
然后兴冲冲交一下,大概可以得到 \(70-80\) 不等的分数,其余全部TLE。
这个 \(\color{black}{\texttt{C}} \color{red}{\texttt{YJian}}\) 怎么这么毒瘤啊
然后问了 \(\color{black}{\texttt{c}} \color{red}{\texttt{yn2006}}\),他告诉我全是快速幂的问题,跑的太满了。
一开始还以为是线性筛的问题/kk。
实测:
线性筛:\(0.04s\)
快速幂:\(1.02s\)
接着开始优化:
于是 \(n\) 次快速幂被优化成了 \(n\) 次乘法加一次快速幂,交了一发就过了。
但是 \(\color{black}{\texttt{c}} \color{red}{\texttt{yn2006}}\) 又告诉我可以优化一倍常数。
for(int i=1;i<=n;++i)fm=1ll*fm*qpow(qpow(i,phi[n/i]*2-1),mod-2)%mod;
可以变成
for(int i=1;i<=n;++i)fm=1ll*fm*qpow(i,(phi[n/i]<<1)-1)%mod;
fm=qpow(fm,mod-2);
少了 \(n\) 次快速幂。
最终本地 \(0.1s\) ,优化了 \(10\) 倍常数((
卡常太恐怖了!!!
给个大样例以供调试:
Input
1000000
Output
101067080
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return x*f;
}
const int N=1000005;
const int mod=104857601;
int n,fz=1,fm=1,ans;
int pri[785050],cnt,phi[N];
bool vis[N];
inline int qpow(int x,int y,int ret=1){
for(;y;y>>=1,x=1ll*x*x%mod) if(y&1)
ret=1ll*ret*x%mod; return ret;
}
void qmod(int&x,int mod){
x+=x>>31&mod,x-=mod,x+=x>>31&mod;
}
void Sieve(const int&N) {
phi[1]=1;
for (int i=2;i<=N;++i){
if(!vis[i])pri[++cnt]=i,phi[i]=i-1;
for (int j=1;j<=cnt&&i*pri[j]<=N;++j) {
vis[i*pri[j]]=1;
if (i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}
phi[i*pri[j]]=phi[i]*phi[pri[j]];
}
}
for(int i=1;i<=N;++i)qmod(phi[i]+=phi[i-1],mod-1);
}
signed main(){
n=read(),Sieve(n);
for(int i=1;i<=n;++i)fz=1ll*i*fz%mod;fz=qpow(fz,n<<1);
for(int i=1;i<=n;++i)fm=1ll*fm*qpow(i,(phi[n/i]<<1)-1)%mod;
fm=qpow(fm,mod-2);
ans=1ll*fz*fm%mod*fm%mod,printf("%d\n",ans);
return 0;
}