ARC051 C - 掛け算

解法

愚直にシミュレーションするとB≦109なのでTLEしてしまう。

操作を十分な回数行うと、一番小さい数にAをかけると一番大きな数になる状態ができる。

この状態になれば周期性を利用してとくことができる。

この状態になった時の数列が{a'}で残りの操作回数がB'回の時、

i = B' % N とすると、

a'_0 ~ a'_{i-1} は B' / N + 1 回、

a'_i ~ a'_{N-1} は B' / N 回

Aをかける。

愚直にAをかけるとTLEなのでダブリングを用いる。

出力は a'_i, ..., a'_{N-1}, a'_0, ... , a'_{i-1}の順ですれば良い。

コード

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <bitset>
#include <cstring>
#include <deque>
using namespace std;
#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
#define CLR(mat) memset(mat, 0, sizeof(mat))
typedef long long ll;
const ll MOD = 1000000007;
int main()
{
  ios::sync_with_stdio(false);
  cin.tie(0);
  ll N, A, B; cin >> N >> A >> B;
  ll a[N];
  priority_queue<ll, vector<ll>, greater<ll> > Q;
  FOR(i,0,N) {
    cin >> a[i];
    Q.push(a[i]);
  }
  sort(a, a + N);
  if(A == 1) {
    FOR(i,0,N) cout << a[i] % MOD << endl;
    return 0;
  }
  while(Q.top() < a[N-1]) {
    B--;
    ll q = Q.top(); Q.pop();
    Q.push(q * A);
    if(B == 0) break;
  }
  FOR(i,0,N) {
    a[i] = Q.top();
    Q.pop();
  }
  if(B == 0) {
    FOR(i,0,N) cout << a[i] % MOD << endl;
    return 0;
  }
  // 残りB回N回周期
  FOR(i,0,N) {
    int j = (i + B % N) % N;
    ll x = a[j] % MOD;
    ll t = j < B % N ? B / N + 1 : B / N;
    ll AA = A % MOD;
    // ダブリング
    while(t) {
      if(t & 1) x = (x * AA) % MOD;
      AA = (AA * AA) % MOD;
      t >>= 1;
    }
    cout << x << endl;
  }
  return 0;
}