前言
废物只会前四题了,在手机上敲得题解大家将就看
题解
A.Wakey Wakey
任意长度区间都存在绝对众数,考虑区间长度为2时,任意相邻两项都相等,所以整个序列就只有一种数字,输出m%p即可
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
void solve() {
int n, m, p;
std::cin >> n >> m >> p;
std::cout << m % p << '\n';
}
signed main() {
std::ios::sync_with_stdio(0);
std::cout.tie(0);
std::cin.tie(0);
i64 t = 1;
std::cin >> t;
while (t--) {
solve();
}
}
B.Substring Not Subsequence
题意为,有多少种字符串仅作为子串出现且不作为不连续的子序列出现,那我们考虑abb,ab就不是一个合法的目标串,因为下标1,2为子串ab,下标1,3为不连续的子序列ab,再考虑aab,下标2,3为子串ab,下标1,3为不连续的子序列ab,所以ab也不是合法序列,你可以多举几个例子发现,如果要满足目标串,我们枚举子串的左端点,如果当前枚举的左端点是第一次出现的字符,那就找后面有多少种字符只出现过一次,这就是答案
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
s = ' ' + s;
std::vector<int> suf(n + 2);
std::map<char, int> mp;
int cnt = 0;
for (int i = n; i >= 1; i--) {
if (!mp[s[i]]) {
suf[i] = suf[i + 1] + 1;
cnt++;
mp[s[i]] = 1;
}
else {
suf[i] = suf[i + 1];
}
}
mp.clear();
int ans = 0;
for (int i = 1; i <= n; i++) {
if (!mp[s[i]]) {
ans += suf[i + 1];
mp[s[i]] = 1;
}
}
std::cout << ans + cnt << '\n';
}
signed main() {
std::ios::sync_with_stdio(0);
std::cout.tie(0);
std::cin.tie(0);
i64 t = 1;
// std::cin >> t;
while (t--) {
solve();
}
}
C.序列
0011为一对,而且每一对00一定会对应固定的11,是不是就很像括号匹配了,我们再考虑如果一对0011可以直接删除,那他跟其他括号的删除就没有先后关系,我们来看最后一个样例,下标1和6对应的00是一对,这一对0011只能在下标2和下标3的00和下标为7和8的00删除之后才能删除,那我们把删除每个0011看成一个事件,最后一个样例即有ABCDE五个事件,其中下标1和6对应的00删除的事件我们认为他是事件C,五个事件没有约束发生的情况一共有A(5,5)种,但C事件必须在AB事件都发生之后才能发生,那去重一下就是A(5,5)/3=40种,所以我们就计算每一对0011会至少在多少对0011删除之后删除,用A(n,n)/(我们算出来每对0011至少在多少对0011删除之后才能删除的数值的乘积)就是答案,我们要维护每一对0011删除之前至少要删除多少对就可以给每一对0011打一个时间戳,我是按照入栈时间把每一对0011打上时间戳,然后用mex去维护的这东西,大家看看代码,不明白的再问我吧
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
const i64 mod = 1e9 + 7;
i64 ksm(i64 a, i64 b) {
i64 res = 1;
while(b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void solve() {
i64 n;
std::cin >> n;
std::string s;
std::cin >> s;
s = ' ' + s;
std::stack<i64> st;
std::vector<i64> cnt(n * 4 + 1);
i64 cnt0 = 0, cnt1 = 0, num = 0;
bool flag = 0;
for (i64 i = 1; i <= 4 * n; i++) {
st.push(i);
if (s[i] == '0') {
cnt0++;
}
else {
cnt1++;
if (cnt1 + cnt0 >= 4) {
std::vector<i64> v;
for (i64 j = 1; j <= 4; j++) {
v.push_back(st.top());
st.pop();
}
if (s[v[0]] == '1' && s[v[1]] == '1' && s[v[2]] == '0' && s[v[3]] == '0') {
cnt1 -= 2;
cnt0 -= 2;
num++;
cnt[v[0]] = num;
cnt[v[1]] = num;
cnt[v[2]] = num;
cnt[v[3]] = num;
}
else {
for (i64 j = 3; j >= 0; j--) {
st.push(v[j]);
}
}
}
}
}
if (st.size()) {
std::cout << 0 << '\n';
return;
}
i64 res = 1;
std::vector<i64> mp(n + 1);
std::set<i64> stt;
for (i64 i = 1; i <= n; i++) {
stt.insert(i);
}
for (i64 i = 1; i <= 4 * n; i++) {
if (!mp[cnt[i]]) {
i64 q = *stt.begin();
res = res * (cnt[i] - q + 1) % mod;
stt.erase(cnt[i]);
mp[cnt[i]] = 1;
}
}
i64 ans = 1;
for (i64 i = 1; i <= n; i++) {
ans = ans * i % mod;
}
// std::cout << ans << ' ' << res << '\n';
std::cout << ans * ksm(res, mod - 2) % mod << '\n';
}
signed main() {
std::ios::sync_with_stdio(0);
std::cout.tie(0);
std::cin.tie(0);
i64 t = 1;
std::cin >> t;
while (t--) {
solve();
}
}
D.数据结构
跟出题人哥哥学的解法,求出初始的sum和,线段树维护每个区间奇偶数的数量,update的时候每次直接推到一个区间只有奇数或只有偶数的区间,具体细节看代码吧,我觉得出题人哥哥写的还是比较明确的
#include <bits/stdc++.h>
#define lowbit(x) x & (-x)
using i64 = long long;
using u64 = unsigned long long;
#define lson (rt << 1)
#define rson (rt << 1 | 1)
int a[500005];
const int mod = 998244353;
i64 ans = 0;
struct treenode {//1是奇,2是偶
int cnt1, cnt2;
int mx, mn;
int lz;
};
struct Segment_Tree {
std::vector<treenode> tr;
void init (int n) {
tr.resize((n + 1) << 2);
build(1, 1, n);
}
void merge (int rt) {
tr[rt].mn = std::min(tr[lson].mn, tr[rson].mn);
tr[rt].mx = std::max(tr[lson].mx, tr[rson].mx);
tr[rt].cnt1 = tr[lson].cnt1 + tr[rson].cnt1;
tr[rt].cnt2 = tr[lson].cnt2 + tr[rson].cnt2;
}
void push_down(int rt) {
if (tr[rt].lz) {
update(lson, tr[rt].lz);
update(rson, tr[rt].lz);
tr[rt].lz = 0;
}
}
void build(int rt, int l, int r) {
if (l == r) {
tr[rt].mn = tr[rt].mx = a[l];
if (a[l] & 1) {
tr[rt].cnt1 = 1;
}
else {
tr[rt].cnt2 = 1;
}
return;
}
int mid = l + r >> 1;
build(lson, l, mid);
build(rson, mid + 1, r);
merge(rt);
}
void update(int rt, int x) {
tr[rt].mn += x;
tr[rt].mx += x;
if (x & 1) {
std::swap(tr[rt].cnt1, tr[rt].cnt2);
}
tr[rt].lz += x;
}
void query1(int rt, int l, int r, int L, int R) {
if (!tr[rt].cnt1 || (L > tr[rt].mx || R < tr[rt].mn)) {
return;
}
if (L <= tr[rt].mn && R >= tr[rt].mx && !tr[rt].cnt2) {
ans -= tr[rt].cnt1;
update(rt, -1);
return;
}
push_down(rt);
int mid = l + r >> 1;
query1(lson, l, mid, L, R);
query1(rson, mid + 1, r, L, R);
merge(rt);
}
void query2(int rt, int l, int r, int L, int R) {
if (!tr[rt].cnt2 || (L > tr[rt].mx || R < tr[rt].mn)) {
return;
}
if (L <= tr[rt].mn && R >= tr[rt].mx && !tr[rt].cnt1) {
ans -= tr[rt].cnt2;
update(rt, -1);
return;
}
push_down(rt);
int mid = l + r >> 1;
query2(lson, l, mid, L, R);
query2(rson, mid + 1, r, L, R);
merge(rt);
}
}tr;
void solve() {
int n, q;
std::cin >> n >> q;
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
ans += a[i];
}
std::sort(a + 1, a + 1 + n);
tr.init(n);
i64 res = 0;
for (int i = 1; i <= q; i++) {
int l, r, c;
std::cin >> l >> r >> c;
if (c == 0) {
tr.query2(1, 1, n, l, r);
}
else {
tr.query1(1, 1, n, l, r);
}
res ^= i * ans;
}
std::cout << res << '\n';
}
signed main() {
std::ios::sync_with_stdio(0);
std::cout.tie(0);
std::cin.tie(0);
i64 t = 1;
// std::cin >> t;
while (t--) {
solve();
}
}