题解 P6273 【[eJOI2017]魔法】
【P6273】 [eJOI2017]魔法
Solution
写了个看起来不会被卡的暴力交上去过了,然后看看官方题解发现这居然就是正解……
首先考虑子任务三,字符集大小只有
考虑枚举右端点,对于一个右端点
对上式移项得到
于是从左到右枚举
对于子任务四,发现字符集扩大到了 std::map 中,查询时直接查询对应元素的个数即可。时间复杂度
当然,如果希望理性愉悦的话,可以用 hash 代替 std::map,再用线段树维护对前缀和差值的区间加,即可将复杂度降至
另外说句闲话,std::multiset.count 的复杂度竟然是
Code
const int maxn = 100005;
const int maxk = 52;
void Init();
void Calc();
int main() {
freopen("1.in", "r", stdin);
Init();
Calc();
return 0;
}
int n, t;
char s[maxn];
void Init() {
static char tmp[maxn];
qr(n);
qrs(s + 1);
for (int i = 1; i <= n; ++i) tmp[i] = s[i];
std::sort(tmp + 1, tmp + 1 + n);
t = std::unique(tmp + 1, tmp + 1 + n) - tmp - 1;
for (int i = 1; i <= n; ++i) s[i] = std::lower_bound(tmp + 1, tmp + 1 + t, s[i]) - tmp - 1;
}
struct Dat {
int d[maxk];
bool operator<(const Dat &o) const {
for (int i = 0; i < t; ++i) if (d[i] != o.d[i]) {
return d[i] < o.d[i];
}
return false;
}
};
Dat dat[maxn];
struct Cmp {
inline bool operator()(const int x, const int y) const {
return dat[x] < dat[y];
}
};
std::map<int, int, Cmp> mp;
void Calc() {
ll ans = 0;
mp[0] = 1;
for (int i = 1, di = i - 1; i <= n; di = i++) {
for (int j = 0; j < t; ++j) {
dat[i].d[j] = dat[di].d[j];
}
if (s[i]) {
++dat[i].d[s[i]];
} else {
for (int j = 1; j < t; ++j) --dat[i].d[j];
}
int u = mp[i];
ans += u;
mp[i] = u + 1;
}
qw(ans % 1000000007, '\n');
}