2023-11-04 21:41阅读: 602评论: 1推荐: 1

AtCoder Beginner Contest 327

2023.11.08 update: 更新了G

A - ab (abc327 A)

题目大意

给定一个字符串s,问是否包含 abba

解题思路

遍历判断即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
string s;
cin >> n >> s;
bool ok = false;
for (int i = 1; i < n; ++i) {
ok |= (s[i] == 'a' && s[i - 1] == 'b');
ok |= (s[i - 1] == 'a' && s[i] == 'b');
}
if (ok)
cout << "Yes" << '\n';
else
cout << "No" << '\n';
return 0;
}


B - A^A (abc327 B)

题目大意

给定b,问是否存在 a使得 aa=b

解题思路

由于指数爆炸的缘故,a的范围不会很大,枚举a,看b%a是否为 0,然后用b不断除以 a ,看最后除的次数是否等于a

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
LL b;
cin >> b;
int ans = -1;
for (int i = 2; i <= 20; ++i) {
if (b % i != 0)
continue;
LL x = b;
int cnt = 0;
while (x > 1) {
x /= i;
++cnt;
}
if (cnt == i) {
ans = i;
break;
}
}
if (b == 1)
ans = 1;
cout << ans << '\n';
return 0;
}


C - Number Place (abc327 C)

题目大意

给定一个9×9的网格,问是否符合数独局面。

数独局面,即每行 19,每列 19,每个 3×3的格子有 19

解题思路

按照条件,逐行、逐列、逐格子分别判断即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
array<array<int, 9>, 9> a;
for (auto& i : a)
for (auto& j : i)
cin >> j;
auto ok = [&]() {
for (auto& i : a) {
if (set<int>(i.begin(), i.end()).size() != 9)
return false;
}
for (int i = 0; i < 9; ++i) {
set<int> cnt;
for (int j = 0; j < 9; ++j) {
cnt.insert(a[j][i]);
}
if (cnt.size() != 9)
return false;
}
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
set<int> cnt;
for (int x = 0; x < 3; ++x)
for (int y = 0; y < 3; ++y) {
cnt.insert(a[i * 3 + x][j * 3 + y]);
}
if (cnt.size() != 9)
return false;
}
}
return true;
};
if (ok())
cout << "Yes" << '\n';
else
cout << "No" << '\n';
return 0;
}


D - Good Tuple Problem (abc327 D)

题目大意

给定两个数组长度为m,仅包含1na,b,问它们是否是一对好数组。

若两个数组是一对好数组,则存在一个长度为n01数组 x,使得 xaixbi,i[1,m]

解题思路

将条件抽象成图,相当于是点ai和点bi连一条边,它们的颜色不能相同。

即最后是否是一张二分图,黑白染色即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<int> a(m), b(m);
for (auto& i : a) {
cin >> i;
--i;
}
for (auto& i : b) {
cin >> i;
--i;
}
vector<vector<int>> edge(n);
for (int i = 0; i < m; ++i) {
edge[a[i]].push_back(b[i]);
edge[b[i]].push_back(a[i]);
}
vector<int> col(n, -1);
bool ok = true;
auto BFS = [&](int st) {
queue<int> team;
team.push(st);
col[st] = 0;
while (!team.empty()) {
int u = team.front();
team.pop();
int target = (col[u] ^ 1);
for (auto& v : edge[u]) {
if (col[v] == -1) {
col[v] = target;
team.push(v);
} else if (col[v] != target) {
ok = false;
return;
}
}
}
};
for (int i = 0; i < n && ok; ++i) {
if (col[i] == -1)
BFS(i);
}
if (ok)
cout << "Yes" << '\n';
else
cout << "No" << '\n';
return 0;
}


E - Maximize Rating (abc327 E)

题目大意

给定n场比赛的表现分pi,现在选择一些场比赛,使得这些场比赛的 rating最大。

如果选择了 k场比赛 (q1,q2,...,qk),则 rating

i=1k(0.9)kiqii=1k(0.9)ki1200k

注意这里的q要按照原来的顺序排列。

解题思路

枚举k,有几项就变成常数,唯一的变数就是最大化i=1k(0.9)kiqi,这其实就是个经典的背包问题。

dp[i][j]表示前 i场比赛,我选择了j场的i=1k(0.9)kiqi的最大值。

转移就是考虑当前比赛选或不选,则dp[i][j]=max(dp[i1][j],dp[i1][j1]0.9+pi)

初始条件就是dp[0][0]=0

答案就是max(dp[n][k]i=1k(0.9)ki1200k)

时间复杂度是O(n2)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const double inf = numeric_limits<double>::max();
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<double> dp(n + 1, -inf);
dp[0] = 0;
for (int i = 0; i < n; ++i) {
vector<double> dp2 = dp;
int p;
cin >> p;
for (int j = 1; j <= i + 1; ++j) {
dp2[j] = max(dp2[j], dp[j - 1] * 0.9 + p);
}
dp2.swap(dp);
}
double ans = -inf;
double bottom = 1;
for (int i = 1; i <= n; ++i) {
ans = max(ans, dp[i] / bottom - 1200 / sqrt(i));
bottom = bottom * 0.9 + 1;
}
cout << fixed << setprecision(10) << ans << '\n';
return 0;
}


F - Apples (abc327 F)

题目大意

二维平面,给定若干个点,问一个长宽为d×w的矩形所能覆盖的点的数量的最大值。

解题思路

枚举一个维度i(时间),问题就是在[i,i+d)的范围内的另一维度(地点)的宽度为w的点数的最大值。

设数组a[i]表示 sum[i,i+w),即当前时间范围内的一个区间的点数,随着时间的流逝,会有新的点加入,会有旧的点删去。其影响的都是一个长度为 wa区间,用线段树维护这个数组 a即可。

时间复杂度为O(nlogn)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 2e5 + 8;
class segtree {
#define lson (root << 1)
#define rson (root << 1 | 1)
int max[N << 2], lazy[N << 2];
inline void pushdown(int root) {
if (lazy[root]) {
lazy[lson] += lazy[root];
max[lson] += lazy[root];
lazy[rson] += lazy[root];
max[rson] += lazy[root];
lazy[root] = 0;
}
}
void update(int root, int l, int r, int L, int R, LL val) {
if (L <= l && r <= R) {
lazy[root] += val;
max[root] += val;
return;
}
pushdown(root);
int mid = (l + r) >> 1;
if (L <= mid)
update(lson, l, mid, L, R, val);
if (R > mid)
update(rson, mid + 1, r, L, R, val);
max[root] = std::max(max[lson], max[rson]);
}
int query(int root, int l, int r) { return max[root]; }
public:
int n;
void update(int L, int R, LL val) { update(1, 1, n, L, R, val); }
int query() { return query(1, 1, n); }
};
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, d, w;
cin >> n >> d >> w;
vector<array<int, 2>> apple(n);
for (auto& i : apple)
cin >> i[0] >> i[1];
vector<int> id(n);
iota(id.begin(), id.end(), 0);
ranges::sort(id, [&](int a, int b) { return apple[a][0] < apple[b][0]; });
segtree seg;
seg.n = N - 8;
auto it = id.begin();
int ans = 0;
for (auto& i : id) {
while (it != id.end() && apple[*it][0] + d <= apple[i][0]) {
seg.update(max(1, apple[*it][1] - w + 1), apple[*it][1], -1);
it = next(it);
}
seg.update(max(1, apple[i][1] - w + 1), apple[i][1], 1);
ans = max(ans, seg.query());
}
cout << ans << '\n';
return 0;
}


G - Many Good Tuple Problems (abc327 G)

题目大意

若两个数组是一对好数组,则存在一个长度为n01数组 x,使得 xaixbi,i[1,m]

问所有的长度为m,仅包含 1n的共 n2m对数组中,好数组的数量。

解题思路

注意到一对数组是好数组,我们将每一位的数字连一条边,这意味着它们所形成的图是一张二分图。

考虑对这个二分图计数。

首先这个二分图会有重边,我们将重边都看成一条边,即设f[i][j]表示 i个点 j条边的简单二分图的方案数。

它跟答案之间差了个常数xm,j——将m相互区分的边分配到这 j相互区分的边集合,且每个集合不为空的方案数。

注意到第二类斯特林数s(i,j)表示将 i相互区分的球放到 j互不区分的盒子的方案数, 则有xi,j=s(i,j)×j!。不过其实它可以通过二项式反演得到:设ym,i意义类似xm,i,但集合可以为空,有ym,i=im=j=0i(ij)xm,j,根据二项式反演即得

xm,i=j=0i(1)ij(ij)ym,j=j=0i(1)ij(ij)jm=j=0ii!(1)ijjmj!(ij)!

这样我们可以在O(n4logm)求出 xm,i

注意到一条边(u,v),我们可以让 si=u,ti=v,也可以 si=v,ti=u,因此有两种构造数组的方式,所有还有个 2m的系数。

由此 ans=i=1maxL2mf[n][i]×x(m,i),其中maxL表示可能的最大的边数,显然是左右点数均分,为n2×n2

以下考虑如何求f[i][j]

注意到二分图是可以将点分成左右两部分,由此可以枚举左边部分点(白色点)的数量k,注意到点标号不影响结果,因此方案数有 (ik)

然后考虑连边情况,每一条边都是从左边k个点选一个点,右边 ik个点选一个点,然后连边,因此方案数是(k(nk)j)

但思考会发现上述结果并不是f[i][j],注意到一个比较显然的情况,连边并不保证二分图联通,可能会有单独的一个点。在上述方案计算中,我们会分别考虑该点处于左边(染成了白色)和右边的情况,而在 f[i][j]表示的情况中,应当只考虑一次。进一步的,对于一个有k个连通块的合法二分图,它对于 f[i][j]的贡献是 1,但上述结果计算得来的贡献是 2k,因为每个二分图的染色方案有两种。

我们记上述的结果为 h[i][j],即 i个点j条边的二分图的染色的方案数。注意到上述算重的因素是连通块个数,但从h[i][j]中难以知晓连通块个数的信息,难以从 h[i][j]中得到 f[i][j]

怎么办呢,注意到关键还是连通块个数的问题,转换需要一个桥梁。我们设g[i][j]表示 i个点 j条边的连通的二分图的染色的方案数。即连通块数为1的方案数。

hg的区别仅仅是连通块个数的问题,可以通过容斥得到g[i][j]

考虑从h[i][j]减去不合法的情况,即 1号点(其实是标号最小的点,1号点方便理解)的连通块个数不是 i的情况,通过枚举其点数和边数以及点的标号情况,有g[i][j]=h[i][j]k=1il=0j(i1k1)g[k][l]h[ik][jl]

g[i][j]是一个连通块的染色方案数,那二分图的方案数就是 g[i][j]2。即设 a[i][j]=g[i][j]2表示 i个点 j条边的连通的二分图的方案数。

af的区别仅仅是连通块个数的问题,同 hg的关系,可以通过容斥得到 f[i][j]

同样考虑枚举1号点所在连通块的点数、边数和点的标号的情况,有f[i][j]=k=1il=0j(i1k1)a[k][l]f[ik][jl]

由此得到f[i][j],就能得到答案了。

综上,我们设

  • f表示二分图的方案数
  • a表示连通二分图的方案数
  • h表示二分图染色的方案数
  • g表示连通二分图染色的方案数

然后h通过枚举染白色的点数量很轻易地求出,由于染色和二分图之间存在关于连通块个数的关系, 需要一个连通(连通块个数为1)作为桥梁,通过 hgaf

  • h[i][j]=k=0i(ik)(k(ik)j)
  • g[i][j]=h[i][j]k=1il=0j(i1k1)g[k][l]h[ik][jl]
  • a[i][j]=g[i][j]2
  • f[i][j]=k=1il=0j(i1k1)a[k][l]f[ik][jl]

注意初值条件f[0][0]=1

最后再通过一个组合数得到ans=i=1maxL2mf[n][i]×xm,i

其中xm,i=j=0i(1)ij(ij)jm表示将m相互区分的球放到 i相互区分的盒子,且每个盒子非空的方案数。

总的时间复杂度是O(n6+n4logm)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define FOR(i, x, y) \
for (decay<decltype(y)>::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) \
for (decay<decltype(x)>::type i = (x), _##i = (y); i > _##i; --i)
const int mo = 998244353;
const int M = 1e3;
LL bin(LL x, LL n, LL MOD) {
LL ret = MOD != 1;
for (x %= MOD; n; n >>= 1, x = x * x % MOD)
if (n & 1)
ret = ret * x % MOD;
return ret;
}
inline LL get_inv(LL x, LL p) { return bin(x, p - 2, p); }
LL invf[M], fac[M] = {1};
void fac_inv_init(LL n, LL p) {
FOR(i, 1, n)
fac[i] = i * fac[i - 1] % p;
invf[n - 1] = bin(fac[n - 1], p - 2, p);
FORD(i, n - 2, -1)
invf[i] = invf[i + 1] * (i + 1) % p;
}
inline LL C(LL n, LL m) { // n >= m >= 0
return n < m || m < 0 ? 0 : fac[n] * invf[m] % mo * invf[n - m] % mo;
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
fac_inv_init(M, mo);
int n, m;
cin >> n >> m;
int maxL = n / 2 * (n + 1) / 2;
vector<vector<int>> h(n + 1, vector<int>(maxL + 1, 0));
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= maxL; ++j)
for (int k = 0; k <= i; ++k) {
h[i][j] += C(i, k) * C(k * (i - k), j) % mo;
if (h[i][j] >= mo)
h[i][j] -= mo;
}
vector<vector<int>> g(n + 1, vector<int>(maxL + 1, 0));
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= maxL; ++j) {
g[i][j] = h[i][j];
for (int k = 1; k <= i; ++k)
for (int l = 0; l <= j; ++l) {
g[i][j] -=
C(i - 1, k - 1) * g[k][l] % mo * h[i - k][j - l] % mo;
if (g[i][j] < 0)
g[i][j] += mo;
}
}
vector<vector<int>> a(n + 1, vector<int>(maxL + 1, 0));
int inv2 = get_inv(2, mo);
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= maxL; ++j) {
a[i][j] = 1ll * g[i][j] * inv2 % mo;
}
vector<vector<int>> f(n + 1, vector<int>(maxL + 1, 0));
f[0][0] = 1;
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= maxL; ++j)
for (int k = 1; k <= i; ++k)
for (int l = 0; l <= j; ++l) {
f[i][j] +=
C(i - 1, k - 1) * a[k][l] % mo * f[i - k][j - l] % mo;
if (f[i][j] >= mo)
f[i][j] -= mo;
}
vector<int> mm(maxL + 1);
for (int i = 0; i <= maxL; ++i)
mm[i] = bin(i, m, mo);
vector<int> x(maxL + 1);
for (int i = 0; i <= maxL; ++i) {
int sig = 1 - 2 * (i & 1);
for (int j = 0; j <= i; ++j) {
x[i] = (x[i] + C(i, j) * mm[j] % mo * sig) % mo;
if (x[i] < 0)
x[i] += mo;
sig *= -1;
}
}
int ans = 0;
int p2 = bin(2, m, mo);
for (int i = 1; i <= maxL; ++i) {
ans += 1ll * p2 * f[n][i] % mo * x[i] % mo;
if (ans >= mo)
ans -= mo;
}
cout << ans << '\n';
return 0;
}


本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/17809838.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(602)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.