我表示我完全是看题解莫名其妙对了,题目和代码暂存在这里。
如有大牛路过,欢迎留评论
【a^b≡a^(b mod phi(c)+phi(c)) (mod c)(b>=phi(c))】【公式的条件很苛刻,原以为(b>=phi(c))没有意义】
其中phi(c) 是欧拉函数
原题目:
一、超级数
【题目描述】:
众所周知,多次加法运算是乘法,多次乘法运算是乘方,那么多次乘方运算呢?比如:
2^2=4
2^2^2=16
2^2^2^2=65536
现在我需要你的力量来计算出:
a1^a2^a3^a4^a5^...an mod p
但是,这个数光是想想就远远超过了整个宇宙的大小,所以你只要求出它的值MOD P就可以了
【输入】:
第一行两个数N,P,如题目描述。
第二行N个数,表示a1~n。
【输出】:
仅一个数,表示它的值mod p的结果。
【样例输入】:
5 13
2 2 2 2 2
【样例输出】:
3
【说明】:
20%的数据N≤3,ai<1000;
40%的数据ai,p为质数或1;
100%的数据N≤20,ai,p≤Maxlongint。
原题解: 挖掘乘法运算在取摸下的置换规律
(a^b^c^...) mod mo >>> [a^( (b^c^...) mod phi( mo / gcd(mo,a^x) ) ) ] mod mo
{x 只要稍微大一点就可以了,梁盾取的是43,学号==}
既可以递归为子问题。
另外有几个特殊情况,具体见标程。
c++新版:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const int maxu=10000000;
using namespace std;
int phi[maxu+1],n,T,tot,Prim[maxu/10],flag;
long long p,a[21],ans;
bool check[maxu];
long long fgm(long long b,long long e,long long mo)
{
long long sum=1;
int lag=0;
for (;e;e>>=1) {
if (e&1) {
if (flag || b>mo || lag || sum>mo) {
sum=(sum*b)%mo;
flag=lag=1;
}
else sum=sum*b;
}
if (lag || b>mo) {
lag=1;
b%=mo,b=(b*b)%mo;
}
else b=b*b;
}
return sum;
}
long long pow_pow(int x,int p)
{
if (x==n) return a[x];
long long b=pow_pow(x+1,phi[p]);
if (flag || b>=phi[p]) {
flag=1;
b=(b%phi[p])+phi[p];
return fgm(a[x],b,p);
}
else return fgm(a[x],b,p);
}
void origin()
{
phi[1]=1;
tot=0;
for (int i=2;i<=maxu;i++) {
if (!check[i]) Prim[++tot]=i,phi[i]=i-1;
for (int j=1;j<=tot;j++) {
if (Prim[j]*i>maxu) break;
check[Prim[j]*i]=1;
if (i%Prim[j]==0) {
phi[Prim[j]*i]=phi[i]*Prim[j];
break;
}
else {
phi[Prim[j]*i]=phi[i]*phi[Prim[j]];
}
}
}
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
cin>>T;
origin();
for (;T;T--) {
cin>>n>>p;
for (int i=1;i<=n;i++) cin>>a[i];
flag=0;
ans=pow_pow(1,p)%p;
cout<<ans<<endl;
}
return 0;
}
updata1:asdfsfasf2同学后来提了一个反例把我这个程序cha掉了,是算2^1^3 % 4,因为我的程序中找到第一个ai^ai+1^...an >=phi[pi]的时候,就默认以后的运算的次方都会大于等于phi[pj],但是如果序列中有1的话就会出错,这里我现在特判掉了,但不知道还有没有其他问题,所以新程序暂时先不放上来
updata2:又鼓捣了一下,现在目测应该没什么问题了,用三种方式生成数据对拍了很久,以前主要问题在于,1、如果序列中有1的话,使用公式的区间就不能从后面开始确定;2、快速幂的时候,没考虑到判断等于的情况,以及暴界的可能。
然后对于使用公式的区间判定,因为受高一时写的程序的影响,采取从后往前递推判断,除了1之外,不知道有没有其他特例,所以我又写了一遍裸判的,不过貌似原来的判断方式也没有拍出错来。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const int maxu=10000000;
using namespace std;
int phi[maxu+1],n,T,tot,Prim[maxu/10],flag;
long long p,a[21],ans;
bool check[maxu];
long long fgm(long long b,long long e,long long mo,int o)
{
long long sum=1;
for (;e;e>>=1) {
if (e&1) {
if (o && (b>=mo || sum>=mo || sum*b>=mo)) return -1;
else sum=sum*b%mo;
}
if ((b>=mo || b*b>=mo) && o) return -1;
else b=b*b%mo;
}
return sum;
}
long long checkp(int x,long long p)
{
if (x==n) return (a[x]>=p) ? -1 : a[x];
long long ans=a[n];
for (int i=n-1;i>=x;i--) {
ans=fgm(a[i],ans,p,1);
if (ans<0) return -1;
}
return ans;
}
long long pow_pow(int x,long long p)
{
if (x==n) return a[x];
long long flag=checkp(x+1,phi[p]);
if (flag<0) {
long long b=pow_pow(x+1,phi[p]);
b=(b%phi[p])+phi[p];
return fgm(a[x],b,p,0)%p;
}
else {
return fgm(a[x],flag,p,0)%p;
}
}
void origin()
{
phi[1]=1;
tot=0;
for (int i=2;i<=maxu;i++) {
if (!check[i]) Prim[++tot]=i,phi[i]=i-1;
for (int j=1;j<=tot;j++) {
if (Prim[j]*i>maxu) break;
check[Prim[j]*i]=1;
if (i%Prim[j]==0) {
phi[Prim[j]*i]=phi[i]*Prim[j];
break;
}
else {
phi[Prim[j]*i]=phi[i]*phi[Prim[j]];
}
}
}
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
cin>>T;
origin();
for (;T;T--) {
cin>>n>>p;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=n;i>=1;i--)
if (a[i]==1) n=i;
flag=0;
ans=pow_pow(1,p)%p;
cout<<ans<<endl;
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const int maxu=10000000;
using namespace std;
int phi[maxu+1],n,T,tot,Prim[maxu/10],flag;
long long p,a[21],ans;
bool check[maxu];
long long fgm(long long b,long long e,long long mo)
{
long long sum=1;
int lag=0;
for (;e;e>>=1) {
if (e&1) {
if (flag || b>=mo || lag || sum>=mo || sum*b>=mo) {
sum=(sum*b)%mo;
flag=lag=1;
}
else sum=sum*b;
}
if (lag || b>=mo || b*b>=mo) {
lag=1;
b%=mo,b=(b*b)%mo;
}
else b=b*b;
}
return sum;
}
long long pow_pow(int x,int p)
{
if (x==n || a[x]==1) return a[x];
long long b=pow_pow(x+1,phi[p]);
if (flag || b>=phi[p]) {
flag=1;
b=(b%phi[p])+phi[p];
return fgm(a[x],b,p);
}
else return fgm(a[x],b,p);
}
void origin()
{
phi[1]=1;
tot=0;
for (int i=2;i<=maxu;i++) {
if (!check[i]) Prim[++tot]=i,phi[i]=i-1;
for (int j=1;j<=tot;j++) {
if (Prim[j]*i>maxu) break;
check[Prim[j]*i]=1;
if (i%Prim[j]==0) {
phi[Prim[j]*i]=phi[i]*Prim[j];
break;
}
else {
phi[Prim[j]*i]=phi[i]*phi[Prim[j]];
}
}
}
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output2.txt","w",stdout);
cin>>T;
origin();
for (;T;T--) {
cin>>n>>p;
for (int i=1;i<=n;i++) cin>>a[i];
flag=0;
ans=pow_pow(1,p)%p;
cout<<ans<<endl;
}
return 0;
}
hdu4335
计算在0~m中有多少个i满足i^(i!)%p==b
i!<phi[p]显然很少,然后至多到phi[p],指数就不会变了,相当于(i%p)^(phi[p])%p==b,显然i%p有循环节。m==2^64-1时是trick
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define ll unsigned long long
using namespace std;
ll ans,b,p,m;
int v[200000],check[200000],phi[200000],prim[200000],tot,T;
ll fgm(ll b,ll e,ll mo)
{
b%=mo;
ll sum=1;
for (;e;e>>=1,b=(b*b)%mo)
if (e&1) sum=(sum*b)%mo;
return sum;
}
void origin()
{
tot=0,phi[1]=1;
for (int i=2;i<=100000;i++) {
if (!check[i]) prim[++tot]=i,phi[i]=i-1;
for (int j=1;j<=tot;j++) {
if (i*prim[j]>100000) break;
check[i*prim[j]]=1;
if (i%prim[j]) phi[i*prim[j]]=phi[i]*phi[prim[j]];
else {
phi[i*prim[j]]=phi[i]*prim[j];
break;
}
}
}
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
cin>>T;
origin();
for (int t=1;t<=T;t++) {
cin>>b>>p>>m;
if (1==p && 0==b) {
if (m!=18446744073709551615LLU) cout<<"Case #"<<t<<": "<<m+1<<endl;
else cout<<"Case #"<<t<<": 18446744073709551616"<<endl;
continue;
}
ll sum,i,j,k;
ans=0;
for (i=0,sum=1;sum<phi[p] && i<=m;++i,sum*=i)
if (fgm(i,sum,p)==b) ans++;
for (sum%=phi[p];sum && i<=m;++i,sum=(sum*i)%phi[p])
if (fgm(i,sum+phi[p],p)==b) ans++;
if (i<=m) {
ll cnt=0;
for (j=i;i<=m && (v[i%p]!=t);i++) {
ll tmp=fgm(i,phi[p],p);
if (tmp==b) cnt++;
v[i%p]=t;
}
if (i<=m) {
k=i-j;
ans+=(m-j+1)/k*cnt;
if ((m-j+1)%k) {
i=j+(m-j+1)/k*k;
for (;i<=m;i++)
if (fgm(i,phi[p],p)==b) ans++;
}
}
else ans+=cnt;
}
cout<<"Case #"<<t<<": "<<ans<<endl;
}
return 0;
}