mayoko’s diary

プロコンとかいろいろ。

TCO15 Round 2D easy:BalancedSubstrings

TCO15 Round 2D に参加しました。easy 解くのが遅すぎてひどかったですが, チャレンジを 1 回成功させたおかげでレート微増してくれました(challenge のありがたみをはじめて感じた)。もちろん Round 3 には進めませんでした。

解法

自分はO(N^2\log N)で解きました。

左と右を決めて真ん中の座標を二分探索する。
そのために memo[i] = (0 <= x <= i にあるs[x] == '1' となる x の数), sum[i] = (0 <= x <= i にあるs[x] == '1' となる x の座標値の和)を前計算しておくと, 中央から左端までのトルク, 中央から右端までのトルクが O(1) で計算できる。

const int MAXN = 2505;
int memo[MAXN], sum[MAXN];

int query(int l, int m, int r) {
    int lnum = memo[m-1] - memo[l-1];
    int rnum = memo[r] - memo[m];
    int left = m * lnum - (sum[m-1]-sum[l-1]);
    int right = sum[r]-sum[m] - rnum*m;
    return right-left;
}

class BalancedSubstrings {
public:
    int countSubstrings(string s) {
        cout << "TEST" << endl;
        int n = s.size();
        memo[0] = 0;
        sum[0] = 0;
        for (int i = 1; i <= n; i++) {
            memo[i] = memo[i-1];
            sum[i] = sum[i-1];
            if (s[i-1] == '1') {
                memo[i]++;
                sum[i] += i;
            }
        }
        int ans = 0;
        for (int l = 1; l <= n; l++) for (int r = l; r <= n; r++) {
            int low = l, high = r+1;
            while (high-low > 1) {
                int med = (high+low)/2;
                if (query(l, med, r) >= 0) low = med;
                else high = med;
            }
            if (query(l, low, r) == 0) ans++;
        }
        return ans;
    }
};