結果

問題 No.2232 Miser's Gift
ユーザー GEX777GEX777
提出日時 2023-03-04 20:00:58
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 227 ms / 2,000 ms
コード長 15,496 bytes
コンパイル時間 1,849 ms
コンパイル使用メモリ 142,612 KB
実行使用メモリ 83,328 KB
最終ジャッジ日時 2024-09-18 01:23:23
合計ジャッジ時間 11,366 ms
ジャッジサーバーID
(参考情報)
judge5 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
5,248 KB
testcase_01 AC 2 ms
5,376 KB
testcase_02 AC 2 ms
5,376 KB
testcase_03 AC 201 ms
83,200 KB
testcase_04 AC 207 ms
83,328 KB
testcase_05 AC 23 ms
11,264 KB
testcase_06 AC 2 ms
5,376 KB
testcase_07 AC 135 ms
5,504 KB
testcase_08 AC 204 ms
83,200 KB
testcase_09 AC 202 ms
83,200 KB
testcase_10 AC 206 ms
83,200 KB
testcase_11 AC 208 ms
83,328 KB
testcase_12 AC 207 ms
83,200 KB
testcase_13 AC 205 ms
83,200 KB
testcase_14 AC 200 ms
83,200 KB
testcase_15 AC 208 ms
83,200 KB
testcase_16 AC 203 ms
83,200 KB
testcase_17 AC 204 ms
83,328 KB
testcase_18 AC 198 ms
83,200 KB
testcase_19 AC 201 ms
83,200 KB
testcase_20 AC 204 ms
83,200 KB
testcase_21 AC 203 ms
83,200 KB
testcase_22 AC 202 ms
83,328 KB
testcase_23 AC 226 ms
83,328 KB
testcase_24 AC 222 ms
83,328 KB
testcase_25 AC 223 ms
83,200 KB
testcase_26 AC 227 ms
83,200 KB
testcase_27 AC 225 ms
83,200 KB
testcase_28 AC 209 ms
83,200 KB
testcase_29 AC 209 ms
83,200 KB
testcase_30 AC 209 ms
83,200 KB
testcase_31 AC 208 ms
83,328 KB
testcase_32 AC 211 ms
83,200 KB
testcase_33 AC 206 ms
83,200 KB
testcase_34 AC 203 ms
83,200 KB
testcase_35 AC 204 ms
83,200 KB
testcase_36 AC 207 ms
83,200 KB
testcase_37 AC 207 ms
83,200 KB
testcase_38 AC 4 ms
6,940 KB
testcase_39 AC 4 ms
6,940 KB
testcase_40 AC 4 ms
6,940 KB
testcase_41 AC 4 ms
6,944 KB
testcase_42 AC 4 ms
6,944 KB
testcase_43 AC 4 ms
6,944 KB
testcase_44 AC 4 ms
6,944 KB
testcase_45 AC 4 ms
6,940 KB
testcase_46 AC 4 ms
6,940 KB
testcase_47 AC 4 ms
6,944 KB
testcase_48 AC 2 ms
6,940 KB
testcase_49 AC 2 ms
6,940 KB
testcase_50 AC 2 ms
6,940 KB
testcase_51 AC 2 ms
6,944 KB
testcase_52 AC 2 ms
6,944 KB
testcase_53 AC 2 ms
6,944 KB
testcase_54 AC 2 ms
6,940 KB
testcase_55 AC 2 ms
6,940 KB
testcase_56 AC 2 ms
6,944 KB
testcase_57 AC 2 ms
6,940 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

// 2023-02-21 update

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <cmath>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <string>
#include <sstream>
#include <climits>
#include <bitset>
#include <deque>
#include <cassert>
#include <list>
#include <queue>
#include <array>
#include <valarray>
#include <complex>
#include <bitset>
#include <random>

using namespace std;

// 独自型定義
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef vector<vvll> vvvll;
typedef vector<string> vs;
typedef vector<char> vc;
typedef vector<vc> vvc;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
using AdjacencyList = map<int, vi>;
using EdgeAdjacencyList = map<int, vector<int, int>>;

// マクロの宣言
#define all(x) x.begin(), x.end()

// 定数宣言
constexpr double PI = 3.141592653589793;
constexpr ll MOD998 = 998244353;
constexpr ll MOD107 = 1'000'000'007;

/****************************************************
*************ここから下は自作ライブラリ**************
****************************************************/

// コンテナの中身を表示, 1行で出力をする, debug用
template <typename T>
void printv(T &a)
{
    for (const auto &x : a)
    {
        cout << x << " ";
    }
    puts("");
    return;
}

// コンテナの中身を表示, 二次元配列用
template <typename T>
void printvv(T &a)
{
    for (const auto &x : a)
    {
        printv(x);
    }
}

// コンテナの中身を表示, pair型
template <typename T>
void print_vpair(const T &a)
{
    for (const auto &x : a)
    {
        cout << "(" << x.first << ", " << x.second << "), ";
    }
    puts("");
    return;
}

template <class T>
inline bool chmin(T &a, T b)
{
    if (a > b)
    {
        a = b;
        return true;
    }
    return false;
}

template <class T>
inline bool chmax(T &a, T b)
{
    if (a < b)
    {
        a = b;
        return true;
    }
    return false;
}

// コンテナの中身を表示, 改行して出力をする, debug用
template <typename T>
void println(T &a)
{
    for (const auto &x : a)
    {
        cout << x << endl;
    }
    return;
}

// 1~Nまでの総和を求める
ll sum_from_1_to_N(ll N)
{
    if (N < 1LL)
    {
        return 0;
    }

    if ((N & 1) == 0) // even
    {
        return N / 2 * (N + 1);
    }
    else // odd
    {
        return (N + 1) / 2 * N;
    }
}

// A~Nまでの総和を求める
ll sum_from_A_to_B(ll A, ll B)
{
    return sum_from_1_to_N(B) - sum_from_1_to_N(A);
}

// a^bを求める, 繰り返し2乗法を用いる,3番目の引数はModを取る場合に設定
ll intPowMod(ll a, ll b, const ll MOD = LLONG_MAX)
{
    ll ans = 1;
    ll A = a;
    while (b > 0)
    {
        int n = b % 2;
        b /= 2;

        if (n == 1)
        {
            ans *= A % MOD;
            ans %= MOD;
        }
        A = ((A % MOD) * (A % MOD)) % MOD;
    }
    return ans;
}

ld arg_to_rad(ld arg)
{
    return (arg * PI / 180.0);
}

ld rad_to_arg(ld rad)
{
    return rad * 180.0 / PI;
}

// C(n, m)を求める
ll combination(const ll n, const ll m)
{
    assert(n >= m); // n>=mは保証される

    ll up = 1;
    ll down = 1;
    for (int i = n; i > n - m; i--)
    {
        up *= i;
    }

    for (int i = m; i >= 2; i--)
    {
        down *= i;
    }

    return up / down;
}

// 動的計画法で前処理,O(N**2)
vvll combination_table(const int MAX_N = 50)
{
    vvll com = vvll(MAX_N + 1, vll(MAX_N + 1, 0)); // 前計算の結果を保存
    com[0][0] = 1;
    for (int i = 1; i <= MAX_N; ++i)
    {
        com[i][0] = 1;
        for (int j = 1; j <= MAX_N; j++)
        {
            com[i][j] = (com[i - 1][j - 1] + com[i - 1][j]);
        }
    }
    return com;
}

// a÷bをMODで割ったあまりを返す関数
ll DivisionMod(ll a, ll b, ll MOD)
{
    return (a * intPowMod(b, MOD - 2, MOD)) % MOD;
}

// C(n, r)をModで割った余りを返す関数, 3番めの引数を入れないと通常のConbination
ll combinationMod(ll n, ll r, ll MOD = LLONG_MAX)
{
    // 分子upを求める
    ll up = 1;
    for (ll i = n - r + 1; i <= n; ++i)
    {
        up = (up * i) % MOD;
    }

    // 分母downを求める
    ll down = 1;
    for (ll i = 1; i <= r; ++i)
        down = (down * i) % MOD;

    return DivisionMod(up, down, MOD);
}

// a,bの最大公約数を求める, A>=B>=0の時, 計算量O(logB)
long long GCD(long long a, long long b)
{
    if (b == 0)
        return a;
    else
        return GCD(b, a % b);
}

// 最小公倍数
ll LCM(ll a, ll b)
{
    return a * b / GCD(a, b);
}

// 素数判定, P->true, not_P->false
bool check_Prime(ll N)
{
    if (N == 2)
        return true;

    if (N == 1 || (N & 1) == 0)
        return false;

    for (ll i = 3; i <= sqrt(N); i += 2)
    {
        if (N % i == 0)
            return false;
    }
    return true;
}

// 素因数分解,key:素数, value:指数のmap<ll,ll>を返す
map<ll, ll> prime_factorize(ll number)
{
    map<ll, ll> table;

    for (ll i = 2; i * i <= number; ++i)
    {
        while (number % i == 0)
        {
            table[i]++;
            number /= i;
        }
    }

    if (number != 1LL)
    {
        table[number]++;
    }
    return table;
}

/* エラストステネス and 高速素因数分解
   prime->IsPrime[i]=i; not prime ->最小の素因数 */
vi Eratosthenes(size_t max_number)
{
    vi IsPrime(max_number + 1);

    // tableの初期化
    for (int i = 1; i < IsPrime.size(); ++i)
    {
        IsPrime[i] = i;
    }

    for (int i = 2; i <= sqrt(max_number); ++i)
    {
        for (int j = i; j <= max_number; j += i)
        {
            if (IsPrime[j] == j)
            {
                IsPrime[j] = i;
            }
        }
    }
    return IsPrime;
}

// O(N)でNの階乗を求める
ll factorial(const ll N)
{
    ll ans = 1;
    for (ll i = 1; i <= N; ++i)
    {
        ans *= i;
    }
    return ans;
}

// Run Length Encoding, ランレングス圧縮
template <typename T>
vector<pair<T, int>> RLE(const vector<T> &A)
{
    vector<pair<T, int>> rle;
    rle.push_back({A.front(), 1});

    for (int i = 1; i < A.size(); ++i)
    {
        if (rle.back().first == A[i])
        {
            rle.back().second++;
        }
        else
        {
            rle.push_back({A[i], 1});
        }
    }
    return rle;
}

vector<pair<char, int>> RLE(const string &S)
{
    vector<pair<char, int>> rle;
    rle.push_back({S.front(), 1});

    for (int i = 1; i < S.size(); ++i)
    {
        if (rle.back().first == S[i])
        {
            rle.back().second++;
        }
        else
        {
            rle.push_back({S[i], 1});
        }
    }
    return rle;
}

void DEBUG_INDICATE()
{
    static int cnt = 0;
    cout << "-----DEBUG: " << cnt++ << "------" << endl;
    return;
}

void DEBUG_INDICATE(const string message)
{
    cout << "-----DEBUG: " << message << "------" << endl;
    return;
}

/* RMQ:[0,n-1] について、区間ごとの最小値を管理する構造体
    update(i,x): i 番目の要素を x に更新。O(log(n))
    query(a,b): [a,b) での最小の要素を取得。O(log(n))
*/
template <typename T>
struct RangeMinimumQuery
{
    const T INF = numeric_limits<T>::max();
    int n;         // 葉の数
    vector<T> dat; // 完全二分木の配列
    RangeMinimumQuery(int n_) : n(), dat(n_ * 4, INF)
    { // 葉の数は 2^x の形
        int x = 1;
        while (n_ > x)
        {
            x *= 2;
        }
        n = x;
    }
    void update(int i, T x)
    {
        i += n - 1;
        dat[i] = x;
        while (i > 0)
        {
            i = (i - 1) / 2; // parent
            dat[i] = min(dat[i * 2 + 1], dat[i * 2 + 2]);
        }
    }
    // the minimum element of [a,b)
    T query(int a, int b) { return query_sub(a, b, 0, 0, n); }
    T query_sub(int a, int b, int k, int l, int r)
    {
        if (r <= a || b <= l)
        {
            return INF;
        }
        else if (a <= l && r <= b)
        {
            return dat[k];
        }
        else
        {
            T vl = query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return min(vl, vr);
        }
    }
};

/* RMQ:[0,n-1] について、区間ごとの最小値を管理する構造体
    update(i,x): i 番目の要素を x に更新。O(log(n))
    query(a,b): [a,b) での最小の要素を取得。O(log(n))
*/
template <typename T>
struct RangeMaximumQuery
{
    const T INF = numeric_limits<T>::min();
    int n;         // 葉の数
    vector<T> dat; // 完全二分木の配列
    RangeMaximumQuery(int n_) : n(), dat(n_ * 4, INF)
    { // 葉の数は 2^x の形
        int x = 1;
        while (n_ > x)
        {
            x *= 2;
        }
        n = x;
    }
    void update(int i, T x)
    {
        i += n - 1;
        dat[i] = x;
        while (i > 0)
        {
            i = (i - 1) / 2; // parent
            dat[i] = max(dat[i * 2 + 1], dat[i * 2 + 2]);
        }
    }
    // the minimum element of [a,b)
    T query(int a, int b) { return query_sub(a, b, 0, 0, n); }
    T query_sub(int a, int b, int k, int l, int r)
    {
        if (r <= a || b <= l)
        {
            return INF;
        }
        else if (a <= l && r <= b)
        {
            return dat[k];
        }
        else
        {
            T vl = query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return max(vl, vr);
        }
    }
};

// Union-Find
struct UnionFind
{
    vector<int> par, rank, siz;

    // 構造体の初期化
    UnionFind(int n) : par(n, -1), rank(n, 0), siz(n, 1) {}

    // 根を求める
    int root(int x)
    {
        if (par[x] == -1)
            return x; // x が根の場合は x を返す
        else
            return par[x] = root(par[x]); // 経路圧縮
    }

    // x と y が同じグループに属するか (= 根が一致するか)
    bool issame(int x, int y)
    {
        return root(x) == root(y);
    }

    // x を含むグループと y を含むグループを併合する
    bool unite(int x, int y)
    {
        int rx = root(x), ry = root(y); // x 側と y 側の根を取得する
        if (rx == ry)
            return false; // すでに同じグループのときは何もしない
        // union by rank
        if (rank[rx] < rank[ry])
            swap(rx, ry); // ry 側の rank が小さくなるようにする
        par[ry] = rx;     // ry を rx の子とする
        if (rank[rx] == rank[ry])
            rank[rx]++;     // rx 側の rank を調整する
        siz[rx] += siz[ry]; // rx 側の siz を調整する
        return true;
    }

    // x を含む根付き木のサイズを求める
    int size(int x)
    {
        return siz[root(x)];
    }
};

/* BIT: 区間和の更新や計算を行う構造体
初期値は a_1 = a_2 = ... = a_n = 0
計算量は全て O(logn)
*/
template <typename T>
struct BIT
{
    int n;         // 配列の要素数(数列の要素数+1)
    vector<T> bit; // データの格納先

    // 構造体の初期化
    BIT(int n_) : n(n_ + 1), bit(n, 0) {}

    // add(i,x): a_i += x とする
    void add(int i, T x)
    {
        for (int idx = i; idx < n; idx += (idx & -idx))
        {
            bit[idx] += x;
        }
    }

    // sum(i): a_1 + a_2 + ... + a_i を計算する
    T sum(int i)
    {
        T s(0);
        for (int idx = i; idx > 0; idx -= (idx & -idx))
        {
            s += bit[idx];
        }
        return s;
    }
};

/*********************************************
*************ライブラリ終わり******************
***********************************************/
template <unsigned mod>
struct RollingHash
{
    vector<unsigned> hashed, power;

    inline unsigned mul(unsigned a, unsigned b) const
    {
        unsigned long long x = (unsigned long long)a * b;
        unsigned xh = (unsigned)(x >> 32), xl = (unsigned)x, d, m;
        asm("divl %4; \n\t"
            : "=a"(d), "=d"(m)
            : "d"(xh), "a"(xl), "r"(mod));
        return m;
    }

    RollingHash(const string &s, unsigned base = 10007)
    {
        int sz = (int)s.size();
        hashed.assign(sz + 1, 0);
        power.assign(sz + 1, 0);
        power[0] = 1;
        for (int i = 0; i < sz; i++)
        {
            power[i + 1] = mul(power[i], base);
            hashed[i + 1] = mul(hashed[i], base) + s[i];
            if (hashed[i + 1] >= mod)
                hashed[i + 1] -= mod;
        }
    }

    unsigned get(int l, int r) const
    {
        unsigned ret = hashed[r] + mod - mul(hashed[l], power[r - l]);
        if (ret >= mod)
            ret -= mod;
        return ret;
    }

    unsigned connect(unsigned h1, int h2, int h2len) const
    {
        unsigned ret = mul(h1, power[h2len]) + h2;
        if (ret >= mod)
            ret -= mod;
        return ret;
    }

    int LCP(const RollingHash<mod> &b, int l1, int r1, int l2, int r2)
    {
        int len = min(r1 - l1, r2 - l2);
        int low = -1, high = len + 1;
        while (high - low > 1)
        {
            int mid = (low + high) / 2;
            if (get(l1, l1 + mid) == b.get(l2, l2 + mid))
                low = mid;
            else
                high = mid;
        }
        return (low);
    }
};

ll solve()
{
    ll N;
    cin >> N;
    string S;
    cin >> S;

    // std::random_device rnd;
    RollingHash<998244353> rh(S);
    RollingHash<998244353> rh2(S);
    // RH rh(S);

    set<ll> A, A2;
    for (int i = 0; i <= S.size() - 2; ++i)
    {
        // cout << 0 << ", i=" << i << " || i+2=" << i+2 << " R=" << S.size() << endl;
        auto L = rh.get(0, i);
        auto R = rh.get(i + 2, S.size());
        int len = S.size() - (i + 2);
        auto s = rh.connect(L, R, len);
        // cout << "L=" << L << " R=" << R << " s=" << s <<" len=" <<len << endl;
        A.insert(s);

        // cout << 0 << ", i=" << i << " || i+2=" << i+2 << " R=" << S.size() << endl;
        auto L2 = rh2.get(0, i);
        auto R2 = rh2.get(i + 2, S.size());
        // int len2 = S.size() - (i + 2);
        auto s2 = rh2.connect(L, R, len);
        // cout << "L=" << L << " R=" << R << " s=" << s <<" len=" <<len << endl;
        A2.insert(s);
    }

    // std::random_device rnd;

    // RH rh(S);

    return max(A.size(), A2.size());
}

int main()
{
    int N, W_MAX;
    cin >> N >> W_MAX;

    vll W(N), V(N);
    for (int i = 0; i < N; ++i)
    {
        cin >> W[i] >> V[i];
    }

    vvll dp(N + 1, vll(W_MAX + 1, -1));
    dp[0][0] = 0;

    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j <= W_MAX; ++j)
        {
            if (dp[i][j] == -1)
                continue;

            if (j + W[i] <= W_MAX)
            {
                chmax(dp[i + 1][j + W[i]], dp[i][j] + V[i]);
            }

            chmax(dp[i + 1][j], dp[i][j]);
        }
    }

    for(int i=1; i<=W_MAX; ++i)
    {
        chmax(dp.back()[i], dp.back()[i-1]);
    }

    // DEBUG_INDICATE("DP.back()");
    // printv(dp.back());

    for (int i = 1; i <= W_MAX; ++i)
    {
        cout << dp.back()[W_MAX] - dp.back()[W_MAX-i] + 1<< endl;
        // cout << ans + 1 << endl;
    }
}
0