牛客周赛 Round 101--幂中幂plus
F-幂中幂plus_牛客周赛 Round 101
问题难点:
1.k最大可达10^18,无法暴力计算每个ci
2.ci的计算为幂套幂,很容易TLE或者溢出
3.mod很小(<=10^6),说明会有循环节出现
解决方案思路:
1.利用c_i=base^{c_{i-1}}%mod这个递推关系,用一个数组提前打表模拟知道循环节出现。
2.对所有ci做前缀和si=c1+c2+...+ci,方便o(1)查询
3.若k再循环节前,否则用舒徐额拆分+循环节前缀和快速计算
-
a[i]
: 表示第 iii 项 cic_ici -
s[i]
: 表示前缀和 si=∑j=1icjs_i = \sum_{j=1}^{i} c_jsi=∑j=1icj -
f[x]
: 记录值为 xxx 的c_i
出现在哪个位置,方便找循环开始的位置
快速幂函数
ll mi(ll a,ll b) {if(!b) return 1;if(b&1) return a * mi(a, b-1) % m;return mi(a*a%m, b/2);
}
手写递归快速幂,计算a^bmodm,效率为logb
主函数
cin >> q;
while (q--) {cin >> n;if (n < N) cout << s[n] % m << endl; // 若在打表范围内,直接查表else {x = N - 1; // 打表到 a[x]res = s[x]; // s[x] 是 c_1 到 c_{x} 的前缀和n -= x; // 还剩下 n 项未处理// y 是 a[x] 在前面出现的位置(说明出现了循环)y = f[mi(b, a[x])]; // 找出循环起点位置c = N - y; // 循环节长度res += (s[x] - s[y-1]) % m * (n / c % m); // 整段循环节累加n %= c; // 剩下不足一整段的部分res += s[y + n - 1] - s[y - 1]; // 补上不足的那一段cout << res % m << endl;}
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
#define ll long long
ll q,n,m,i,j,k,b,c,x,y,res;
ll a[N],s[N],f[N];
ll mi(ll a,ll b)
{if(!b) return 1;if(b&1) return a*mi(a,b-1)%m;return mi(a*a%m,b/2);
}
void solve()
{cin>>b>>a[0]>>m;for(b%=m,i=1;i<N;i++){a[i]=mi(b,a[i-1]);s[i]=s[i-1]+a[i];f[a[i]]=i;}cin>>q;while(q--){cin>>n;if(n<N) cout<<s[n]%m<<endl;else{x=N-1,res=s[x],n-=x;y=f[mi(b,a[x])],c=N-y;res+=(s[x]-s[y-1])%m*(n/c%m);n%=c,res+=s[y+n-1]-s[y-1];cout<<res%m<<endl;}}
}
signed main()
{int t = 1;// cin>>t;while (t--){solve();}return 0;
}