# Educational Codeforces Round 84 (Rated for Div. 2)

### A. Sum of Odd Integers

$$k$$个不同奇数和的最小值为$$k^2$$，那么必须满足:

• $$k,n$$同奇偶；
• $$k^2\leq n$$

Code
/*
* Author:  heyuhhh
* Created Time:  2020/3/23 22:35:41
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;

void run() {
int n, k; cin >> n >> k;
int sq = 1;
while(sq * sq <= n) ++sq;
--sq;
if(k <= sq && k >= 2 - (n & 1)) {
int r = sq - k + 1;
int rr = n - sq * sq;
if((r & 1) != (rr & 1)) cout << "YES" << '\n';
else cout << "NO" << '\n';
} else cout << "NO" << '\n';
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}


### B. Princesses and Princes

Code
/*
* Author:  heyuhhh
* Created Time:  2020/3/23 22:56:10
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;

int n;
bool chk[N];

void run() {
cin >> n;
vector <vector <int>> a(n);
for(int i = 0; i < n; i++) {
int k; cin >> k;
a[i].resize(k);
for(int j = 0; j < k; j++) cin >> a[i][j];
}
for(int i = 0; i <= n; i++) chk[i] = false;
int cnt = 0;
vector <int> r;
for(int i = 0; i < n; i++) {
bool f = false;
for(int j = 0; j < sz(a[i]); j++) {
if(!chk[a[i][j]]) {
f = true;
chk[a[i][j]] = true;
++cnt;
break;
}
}
if(f == false) r.push_back(i);
}
if(cnt == n) cout << "OPTIMAL" << '\n';
else {
cout << "IMPROVE" << '\n';
cout << r[0] + 1 << ' ';
for(int i = 1; i <= n; i++) if(!chk[i]) {
cout << i << '\n';
break;
}
}
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}


### C. Game with Chips

Code
/*
* Author:  heyuhhh
* Created Time:  2020/3/23 23:07:11
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;

int n, m, k;

void run() {
cin >> n >> m >> k;
for(int i = 1; i <= k; i++) {
int x, y; cin >> x >> y;
}
for(int i = 1; i <= k; i++) {
int x, y; cin >> x >> y;
}
string res = "";
for(int i = 0; i < n - 1; i++) res += "U";
for(int i = 0; i < m - 1; i++) res += "L";
for(int i = 0; i < n; i++) {
if(i & 1) {
for(int j = 0; j < m - 1; j++) res += "L";
} else {
for(int j = 0; j < m - 1; j++) res += "R";
}
if(i < n - 1) res += "D";
}
cout << res.length() << '\n';
cout << res << '\n';
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}


### D. Infinite Path

Code
/*
* Author:  heyuhhh
* Created Time:  2020/3/24 0:28:41
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 5;

int n;
int p[N], pos[N], c[N];
bool chk[N];
vector <int> G[N];
vector <int> v;

void dfs(int u) {
chk[u] = true;
v.push_back(c[pos[u]]);
for(auto to : G[u]) if(!chk[to]) dfs(to);
}

int solve(int k) {
for(int i = 0; i < k; i++) {
bool ok = true;
for(int j = i + k; j < sz(v); j += k) {
if(v[j - k] != v[j]) ok = false;
}
if(ok) return k;
}
return n;
}

void run() {
cin >> n;
for(int i = 1; i <= n; i++) G[i].clear(), chk[i] = false;
for(int i = 1; i <= n; i++) {
cin >> p[i]; pos[p[i]] = i;
G[i].push_back(p[i]);
}
for(int i = 1; i <= n; i++) cin >> c[i];
int ans = n;
for(int i = 1; i <= n; i++) if(!chk[i]) {
v.clear();
dfs(i);
int k = sz(v);
for(int j = 1; j * j <= k; j++) if(k % j == 0) {
ans = min(ans, min(solve(j), solve(k / j)));
}
}
cout << ans << '\n';
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}


### E. Count The Blocks

Code



### F. AND Segments

• $$0\leq a_i<2^k$$;
• 对于$$1\leq i\leq m$$$$a[l_i]\&\cdots \&a[r_i]=x_i$$

• 可以按位分别进行考虑。
• 对于每一位，限制条件则为存在某些区间，这上面的数必须为$$1$$；存在另一些区间，二进制位上至少有一个$$0$$
• 显然我们可以想到一个$$dp:dp_{i,j}$$表示考虑了前面$$i$$个位置，最后一次$$0$$出现在$$j$$位置，目前满足所有限制条件右端点不超过$$i$$的方案数。
• 转移分情况考虑：
• 若当前位为$$0$$，那么$$dp_{i,0}=\sum_{j=0}^{i-1} dp_{i-1,j}$$;
• 若当前位为$$1$$，因为我们要满足至少有一个是$$0$$的限制条件，考虑以$$i$$为右端点的限制区间，假设区间左端点最大值为$$k$$，那么$$dp_{i,j}=dp_{i-1,j},j\geq k$$。如果此时从小的地方转移过来会出现连续的$$1$$不满足条件。
• 以上$$dp$$的时间复杂度为$$O(n^2)$$，通过线段树优化则可以达到$$O(nlogn)$$。接下来考虑进一步优化。
• $$pre_i$$表示以$$i$$为右端点的询问区间最大的左端点的值，且满足$$[pre_i,i]$$至少有一个$$0$$。那么有个限制条件即为$$pre_i\geq pre_{i-1}$$
• 注意到$$dp$$转移式中，$$dp_i$$的值都是从$$i-1$$复用，但是当当前这一位为$$1$$$$[pre_{i-1},pre[i]-1]$$这段区间我们必须舍弃，然而对于每个$$i$$这个过程是单调的，所以用一个指针维护一下就行。

Code
/*
* Author:  heyuhhh
* Created Time:  2020/3/24 17:50:08
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 5e5 + 5, MOD = 998244353 ;

int n, k, m;
int l[N], r[N], x[N];
int pre[N], cnt[N];
int dp[N];

int solve(int bit) {
dp[0] = 1;
memset(pre, 0, sizeof(pre));
memset(cnt, 0, sizeof(cnt));
for(int i = 1; i <= m; i++) {
if(x[i] >> bit & 1) ++cnt[l[i]], --cnt[r[i] + 1];
else pre[r[i]] = max(pre[r[i]], l[i]);
}
int s = 1, tail = 0;
for(int i = 1; i <= n; i++) {
cnt[i] += cnt[i - 1];
if(cnt[i]) dp[i] = 0;
else dp[i] = s;
while(tail < pre[i]) {
s -= dp[tail++];
if(s < 0) s += MOD;
}
s += dp[i]; s %= MOD;
}
return s;
}

void run() {
cin >> n >> k >> m;
for(int i = 1; i <= m; i++) {
cin >> l[i] >> r[i] >> x[i];
}
int ans = 1;
for(int bit = 0; bit < k; bit++) {
ans = 1ll * ans * solve(bit) % MOD;
}
cout << ans << '\n';
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}


### G. Letters and Question Marks

• 考虑暴力的方法：$$dp_{i,sta}$$表示前$$i$$个位置，目前确定了的状态为$$sta$$的最大代价，然后对串找子串进行计算。找子串这一过程可以用$$AC$$自动机来，时间复杂度为$$O(n^2\cdot 2^{14}\cdot 14)$$
• 接下来考虑优化：假设$$s$$只存在一个$$?$$，那么我们枚举所有状态时在$$AC$$自动机上面来匹配，每次都会从头开始跑，显然会浪费大量的时间，那么就有一个优化思路：

• 暴力$$dp$$的每次转移，我们都需要找到$$AC$$自动机上面的结点，也就是说其实记录$$s$$串的长度是没有必要的，我们更关心的是$$AC$$自动机上面的结点和状态。那么又有一个优化思路：

Code
/*
* Author:  heyuhhh
* Created Time:  2020/3/25 8:58:08
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 4e5 + 5, M = 1005, MAX = 14;
queue <int> q;
namespace ACAM{
int sz;
int ch[M][MAX];
int cnt[M], fail[M], sum[M];
int newnode() {
memset(ch[++sz], 0, sizeof(ch[sz]));
cnt[sz] = fail[sz] = 0;
return sz;
}
void init() {
sz = -1;
newnode();
}
void insert(char *s, int val) {
int u = 0;
for(int i = 1; s[i]; i++) {
int idx = s[i] - 'a';
if(!ch[u][idx]) ch[u][idx] = newnode();
u = ch[u][idx];
}
sum[u] += val;
}
void build() {
while(!q.empty()) q.pop();
for(int i = 0; i < MAX; i++) {
if(ch[0][i]) q.push(ch[0][i]);
}
while(!q.empty()) {
int cur = q.front(); q.pop();
for(int i = 0; i < MAX; i++) {
if(ch[cur][i]) {
fail[ch[cur][i]] = ch[fail[cur]][i];
sum[ch[cur][i]] += sum[ch[fail[cur]][i]];
q.push(ch[cur][i]);
} else {
ch[cur][i] = ch[fail[cur]][i];
}
}
}
}
};
using namespace ACAM;
int k;
char s[N], t[M];
int go[M];
ll dp[M][1 << MAX], c[M];

void chkmax(ll &x, ll y) {
x = max(x, y);
}

void run() {
cin >> k;
init();
for(int i = 1; i <= k; i++) {
int c;
cin >> (t + 1) >> c;
insert(t, c);
}
build();
for(int i = 0; i <= sz; i++) {
for(int j = 0; j < 1 << MAX; j++) {
dp[i][j] = -1e18;
}
}
dp[0][0] = 0;
for(int i = 0; i <= sz; i++) go[i] = i, c[i] = 0;
cin >> (s + 1);
int cnt = 0;
for(int i = 1; s[i]; i++) {
if(s[i] == '?') {
for(int st = 0; st < 1 << MAX; st++) {
if(__builtin_popcount(st) != cnt) continue;
for(int j = 0; j <= sz; j++) if(dp[j][st] > -1e18) {
for(int t = 0; t < MAX; t++) if(!(st >> t & 1)) {
chkmax(dp[ch[go[j]][t]][st | (1 << t)], dp[j][st] + c[j] + sum[ch[go[j]][t]]);
}
}
}
for(int j = 0; j <= sz; j++) go[j] = j, c[j] = 0;
++cnt;
} else {
for(int j = 0; j <= sz; j++) go[j] = ch[go[j]][s[i] - 'a'], c[j] += sum[go[j]];
}
}
ll ans = -1e18;
for(int st = 0; st < 1 << MAX; st++) {
if(__builtin_popcount(st) == cnt) {
for(int i = 0; i <= sz; i++) {
chkmax(ans, dp[i][st] + c[i]);
}
}
}
cout << ans << '\n';
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}

posted @ 2020-03-25 10:25  heyuhhh  阅读(260)  评论(0编辑  收藏  举报