mayoko’s diary

プロコンとかいろいろ。

SRM 424 div1 hard:ProductOfPrices

これは解きたかったかな〜

問題:TopCoder Statistics - Problem Statement

解法:0〜L-1の座標系に木を植えていくことになる。そこで,以下のような変数を用意する。
cnt[i]:座標iに植えられている木の数
dst[i]:dst[i] = cnt[i] * i
座標xに木を植えることを考える。これにかかるpriceは,
(座標x未満に植えられている木の数)*x - (座標x未満に植えられている木の座標の合計)
+ (座標がxより大きい木の座標の合計) - (座標がxより大きい木の植えられている数)*x
= sum(cnt, 0, x-1)*x - sum(dst, 0, x-1) + sum(dst, x+1, L) - sum(cnt, x+1, L)*x
となる。これをBITで処理すれば良い。

// 0-based Binary Indexed Tree
constexpr int mod = 1e9+7;
template<typename T> struct BIT {
    int max;
    vector<T> bit;
    BIT(int max) : max(max) {bit.resize(max+1);}
    // [0, i)
    T sum(int i) {
        T s = 0;
        while (i > 0) {
            (s += bit[i]) %= mod;
            i ^= i&-i;
        }
        return s;
    }
    // 0-basedな座標iに値xを追加する
    void add(int i, T x) {
        ++i;
        while (i <= max) {
            (bit[i] += x) %= mod;
            i += i&-i;
        }
    }
    // [a, b)
    T sum(int a, int b) {
        return sum(b)-sum(a);
    }
    // sum(0, i) >= wとなる最小のiを求める 存在しなければmaxを返す
    int lb(T w) {
        if (w <= 0) return 0;
        int k = 1;
        while (k <= max) k <<= 1;
        int i = 0;
        for (; k > 0; k >>= 1) if (i+k <= max && bit[i+k] < w) {
            w -= bit[i+k];
            i += k;
        }
        return i+1;
    }
};

class ProductOfPrices {
public:
    int product(int N, int L, int X0, int A, int B) {
        BIT<ll>* cnt = new BIT<ll>(L);
        BIT<ll>* dst = new BIT<ll>(L);
        vector<int> X(N);
        X[0] = X0 % L;
        for (int i = 1; i < N; i++) {
            X[i] = ((ll)X[i-1] * A % L + B) % L;
        }
        ll ret = 1;
        cnt->add(X[0], 1);
        dst->add(X[0], X[0]);
        for (int i = 1; i < N; i++) {
            ll tmp = 0;
            tmp += (cnt->sum(0, X[i])) * X[i];
            tmp += mod - (dst->sum(0, X[i]));
            tmp %= mod;
            tmp += (dst->sum(X[i]+1, L));
            tmp += mod-(cnt->sum(X[i]+1, L)) * X[i];
            tmp %= mod;
            if (tmp < 0) tmp += mod;
            (ret *= tmp) %= mod;
            cnt->add(X[i], 1);
            dst->add(X[i], X[i]);
        }
        return (int)(ret%mod);
    }
};