题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3706
题目大意:定义$S_i=A^imodB$,$T_i=min(S_k|i-A<=k<=i,k>=1)$,让你计算$T_i$的乘积对$B$取余
Sample Input
1 2 3 2 3 4 3 4 5 4 5 6 5 6 7
Sample Output
2 3 4 5 6
emmm,看得有点迷,写个暴力的代码看看就知道是怎么回事了:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; const ll inf=1e18+10; ll qpow(ll a,ll b,ll mod) { a%=mod; ll ans=1; while (b){ if (b&1) ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; } int main() { int n; ll a,b; while (~scanf ("%d%lld%lld",&n,&a,&b)){ ll tot=0,ans=1; for (int i=1; i<=n; i++){ ll s=inf; for (int j=max(1LL,i-a); j<=i; j++) s=min(qpow(a,j,b),s); ans*=s; } printf("%lld ",ans); } return 0; }
emmm,看清楚之后也就知道我们实际上只需要维护一个移动区间的最小值就好了,这很容易想到用单调队列来实现,我们用单调队列维护一个递增的序列,不过他有坐标和值两个变量,那么我们用两个队列来维护就好了,一个保存坐标,一个保存值,那么最小的值就是$qs[head]$了,其坐标为$q[head]$,维护也非常简单,直接上代码了
以下是AC代码:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; const ll inf=1e18+10; const int mac=1e7+10; int q[mac]; ll qs[mac]; int main() { int n; ll a,b; while (~scanf ("%d%lld%lld",&n,&a,&b)){ ll ans=1,s=1; int head=1,tail=0; for (int i=1; i<=n; i++){ s=s*a%b;; if (head>tail || s>=qs[tail]) {q[++tail]=i; qs[tail]=s; ans=ans*qs[head]%b; continue;} while (head<=tail && q[head]<i-a) head++; while (head<=tail && qs[tail]>=s) tail--; q[++tail]=i;qs[tail]=s; ans=ans*qs[head]%b; } printf("%lld ",ans%b); } return 0; }