bzoj3884上帝与集合的正确用法
Posted yoyoball
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3884上帝与集合的正确用法相关的知识,希望对你有一定的参考价值。
Solution
这个。。额。。如果知道扩展欧拉定理的话这题其实。。比较裸的样子
虽然说无限个(2)听起来就很恐怖但是
根据扩展欧拉定理,当(b>p)时,有:
[
a^bequiv a^{b\%varphi(p)+varphi(p)}(mod p)
]
然后看一下那个无限个(2)翻上去的指数。。很明显是(>p)的所以。。这条式子就可以直接用啦
每次我们都用这条式子去进行一个类似降幂的操作,然后模数到到后面会长成:
[
varphi(varphi(varphi(...varphi(p)))))
]
这样。。
进行若干次操作之后会变成(1),那么这个时候无论后面再怎么降下去结果都是固定的了
至于这个若干次操作到底是多少,我们可以感性的理解一下(理性证明不会qwq),(varphi(p))会不断缩小然后每次至少会除去一个(2),所以最多是(log)级别的
那所以直接递归求解就好了
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=1e7+10;
int phi[MAXN],p[MAXN];
bool vis[MAXN];
int T,n;
void prework(int n);
int f(int n);
int ksm(int x,int y,int p);
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d",&T);
prework(MAXN-1);
for (int o=1;o<=T;++o){
scanf("%d",&n);
printf("%d
",f(n));
}
}
void prework(int n){
int cnt=0;
phi[1]=1;
for (int i=2;i<=n;++i){
if (!vis[i]){
phi[i]=i-1;
p[++cnt]=i;
}
for (int j=1;j<=cnt&&p[j]*i<=n;++j){
vis[i*p[j]]=true;
if (i%p[j]==0){
phi[i*p[j]]=phi[i]*p[j];
break;
}
else
phi[i*p[j]]=phi[i]*phi[p[j]];
}
}
}
int f(int p){
if (p==1) return 0;
return ksm(2,f(phi[p])+phi[p],p);
}
int ksm(int x,int y,int mod){
int ret=1,base=x;
for (;y;y>>=1,base=1LL*base*base%mod)
if (y&1) ret=1LL*ret*base%mod;
return ret;
}
以上是关于bzoj3884上帝与集合的正确用法的主要内容,如果未能解决你的问题,请参考以下文章