ルクの競プロ部屋

学生の競プロ生活を見たい人はどぞ

競プロ精選 100 問 by C++<高速なべき乗計算>

はじめに

べき乗大好きです 2問やります

70 NTL_1_B - べき乗

問題はこちらです!
問題文↓

m,nが与えられるので、mⁿを求めてください

繰り返し二乗法をします!
コードはこんな感じです

#include <bits/stdc++.h>
#include <chrono>
using namespace std;
using namespace chrono;
#define rep(i, n) for (ll i = 0; i < (n); ++i)
#define rep1(i, n) for (ll i = 1; i <= (n); ++i)
#define rrep(i, n) for (ll i = n; i > 0; --i)
#define bitrep(i, n) for (ll i = 0; i < (1 << n); ++i)
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define yesNo(b) ((b) ? "Yes" : "No")
using ll = long long;
using ull = unsigned long long;
using ld = long double;
string alphabet = "abcdefghijklmnopqrstuvwxyz";
string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const double pi = 3.141592653589793;
ll smallMOD = 998244353;
ll bigMOD = 1000000007;
int dx[] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};

ll repeated_squaring(ll x, ll y, ll z = bigMOD)
{
    ll ans = 1;
    bitset<64> bits(y);
    string bit_str = bits.to_string();
    reverse(all(bit_str));
    rep(i, 64)
    {
        if (bit_str[i] == '1')
            ans = ans * x % z;
        x = x * x % z;
    }
    return ans;
}

int main()
{
    ll n, m;
    cin >> n >> m;
    cout << repeated_squaring(n, m) << endl;
    return 0;
}

repeated_squaring関数をライブラリとして持っておくと強い

71 Square869120Contest #1 E - 散歩

問題はこちらです!
問題文↓

N個の頂点があり、街i-1とiが結ばれているパスグラフがある
i-1とiの距離はA[i-1]^A[i]である
Q個のクエリが与えられる
初め頂点0からスタートして、0→C[0]→C[1]→...→C[Q-1]→0となるように移動する時、距離の総和を求めてください

まず、全ての頂点間の距離を繰り返し二乗法で求めます
そしたら、クエリを処理するためにLからRまでの区間の和を求めたいです
区間の和といえば累積和なので、累積和テーブルを作成し、O(1)で区間の和を求めます
したがってO(N+Q)で求めることができました
コードはこんな感じです

#include <bits/stdc++.h>
#include <chrono>
using namespace std;
using namespace chrono;
#define rep(i, n) for (ll i = 0; i < (n); ++i)
#define rep1(i, n) for (ll i = 1; i <= (n); ++i)
#define rrep(i, n) for (ll i = n; i > 0; --i)
#define bitrep(i, n) for (ll i = 0; i < (1 << n); ++i)
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define yesNo(b) ((b) ? "Yes" : "No")
using ll = long long;
using ull = unsigned long long;
using ld = long double;
string alphabet = "abcdefghijklmnopqrstuvwxyz";
string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const double pi = 3.141592653589793;
ll smallMOD = 998244353;
ll bigMOD = 1000000007;
int dx[] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};

ll repeated_squaring(ll x, ll y, ll z = bigMOD)
{
    ll ans = 1;
    bitset<64> bits(y);
    string bit_str = bits.to_string();
    reverse(all(bit_str));
    rep(i, 64)
    {
        if (bit_str[i] == '1')
            ans = ans * x % z;
        x = x * x % z;
    }
    return ans;
}

int main()
{
    ll n, q;
    cin >> n >> q;
    vector<ll> a(n);
    rep(i, n) cin >> a[i];

    // 距離を計算.
    vector<ll> dist(n - 1);
    rep(i, n - 1)
    {
        dist[i] = repeated_squaring(a[i], a[i + 1]);
    }

    // 区間の和といえば累積和.
    vector<ll> sum(n);
    sum[0] = 0;
    rep(i, n - 1)
    {
        sum[i + 1] = sum[i] + dist[i];
    }

    // クエリ処理.
    ll now = 0;
    ll ans = 0;
    rep(i, q)
    {
        ll go;
        cin >> go;
        ans += abs(sum[go - 1] - sum[now]);
        ans %= bigMOD;
        now = go - 1;
    }
    ans += abs(sum[0] - sum[now]);
    ans %= bigMOD;
    cout << ans << endl;
    return 0;
}

LとRは大きさが逆になることもあるので注意(ここでは絶対値を取りました)

おわり

べき乗マスターになりましたー
ではまた!
、、、区間DPは知らない子です(いつかやります)