从这里开始

Problem A Triangle

  考虑把三角形移到和坐标轴相交,即

  然后能够用坐标比较简单地计算面积,简单构造一下就行了。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool bolean; #define ll long long const int V = 1e9; ll S; int main() {
scanf("%lld", &S);
if (S == 1000000000000000000ll) {
printf("%d 0 0 0 0 %d\n", V, V);
return 0;
}
int z = S / V;
int y = V;
int x = 1;
int h = S % V;
printf("0 %d %d 0 %d %d\n", y, x, x + z, h);
return 0;
}

Problem B Do Not Duplicate

  你发现 $x$ 如果还会再出现,会把之间的数都删掉,所以 $x$ 向它的后继连一条边。然后模拟一下就行了。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define ll long long const int N = 2e5 + 5; int n;
ll K;
int a[N], h[N];
int fa[N], c[N];
boolean vis[N]; int main() {
scanf("%d%lld", &n, &K);
for (int i = 0; i < n; i++) {
scanf("%d", a + i);
}
for (int i = n - 1; ~i; i--)
h[a[i]] = i + n;
for (int i = n - 1; ~i; i--) {
int suf = h[a[i]];
fa[i] = (suf + 1) % n;
c[i] = (suf + 1) / n;
h[a[i]] = i;
}
int p = 0, q;
vector<int> stk;
do {
vis[p] = true;
stk.push_back(p);
p = fa[p];
} while (!vis[p]);
int sumcost = 0;
do {
q = stk.back();
stk.pop_back();
sumcost += c[q];
} while (q ^ p);
stk.clear();
int x = 0;
while (K - c[x] >= 1 && (x ^ p))
K -= c[x], x = fa[x];
if (x == p)
K = (K - 1) % sumcost + 1;
while (K - c[x] >= 1)
K -= c[x], x = fa[x];
memset(vis, false, sizeof(vis));
for (int i = x; i < n + (K - 1) * n; i++) {
int z = a[i % n];
if (!vis[z]) {
stk.push_back(z);
vis[z] = true;
} else {
int y = 0;
do {
y = stk.back();
stk.pop_back();
vis[y] = false;
} while (y ^ z);
}
}
for (auto x : stk) {
printf("%d ", x);
}
return 0;
}

Problem C GP 2

  考虑一些必要条件:

  • 和为 $3M$
  • 最大值不超过 $2M$
  • 奇数个数不超过 $M$

  可以对最大值和最大奇数或剩下的最大值进行讨论,然后用归纳法证明。

  剩下是基础计数。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define ll long long void exgcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1, y = 0;
} else {
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
} int inv(int a, int n) {
int x, y;
exgcd(a, n, x, y);
return (x < 0) ? (x + n) : (x);
} const int Mod = 998244353; template <const int Mod = :: Mod>
class Z {
public:
int v; Z() : v(0) { }
Z(int x) : v(x){ }
Z(ll x) : v(x % Mod) { } friend Z operator + (const Z& a, const Z& b) {
int x;
return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
}
friend Z operator - (const Z& a, const Z& b) {
int x;
return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
}
friend Z operator * (const Z& a, const Z& b) {
return Z(a.v * 1ll * b.v);
}
friend Z operator ~(const Z& a) {
return inv(a.v, Mod);
}
friend Z operator - (const Z& a) {
return Z(0) - a;
}
Z& operator += (Z b) {
return *this = *this + b;
}
Z& operator -= (Z b) {
return *this = *this - b;
}
Z& operator *= (Z b) {
return *this = *this * b;
}
friend boolean operator == (const Z& a, const Z& b) {
return a.v == b.v;
}
}; Z<> qpow(Z<> a, int p) {
Z<> rt = Z<>(1), pa = a;
for ( ; p; p >>= 1, pa = pa * pa) {
if (p & 1) {
rt = rt * pa;
}
}
return rt;
} typedef Z<> Zi; const int N = 3e6 + 5; int n, m;
Zi fac[N], _fac[N]; void prepare(int n) {
fac[0] = 1;
for (int i = 1; i <= n; i++)
fac[i] = fac[i - 1] * i;
_fac[n] = ~fac[n];
for (int i = n; i; i--)
_fac[i - 1] = _fac[i] * i;
}
Zi comb(int n, int m) {
return (n < m) ? (0) : (fac[n] * _fac[m] * _fac[n - m]);
} int main() {
scanf("%d%d", &n, &m);
prepare(3 * m + n - 1);
Zi ans = comb(3 * m + n - 1, n - 1) - comb(m + n - 2, n - 1) * n;
for (int num = m + 1; num <= n && num <= 3 * m; num++) {
if ((3 * m - num) & 1)
continue;
int sum = (3 * m - num) >> 1;
Zi tmp = comb(sum + n - 1, n - 1);
// mx is odd
tmp -= num * comb(sum - m + n - 1, n - 1);
// mx is even
tmp -= (n - num) * comb(sum - m + n - 2, n - 1);
tmp *= comb(n, num);
ans -= tmp;
}
printf("%d\n", ans.v);
return 0;
}

Problem D Negative Cycle

  设到第 $i$ 个点的最短路为 $d_i$。不难发现 $d_i \geqslant d_{i + 1}$,如果存在负环,那么会更新。

  考虑最短路等于 $d$ 和最短路等于 $d + 1$ 的两段 $[a, b]$,以及 $(b, c]$。

  那么 $(b, c]$ 不能有到 $a$ 之前的边,否则 $d$ 会被更新。$(b + 1, c]$ 之间不能有从前连向后面的边,否则 $d$ 也会被更新。

  状态中记入 $a, b$,稍作优化就能做到 $O(n^3)$。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define ll long long const ll llf = (signed ll) (~0ull >> 2); const int N = 505; int n;
int A[N][N];
ll s[N][N];
ll dp[N][N]; int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j) {
continue;
}
scanf("%d", A[i] + j);
s[i][j] = A[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dp[i][j] = llf;
dp[1][1] = 0;
for (int i = 2; i <= n; i++) {
dp[1][i] = dp[1][i - 1];
for (int j = 1; j < i; j++) {
dp[1][i] += A[j][i];
}
}
for (int i = 2; i <= n; i++) {
ll cost = 0;
for (int b = i - 1; b; b--) {
for (int j = b + 2; j <= i; j++)
cost += A[b + 1][j];
for (int a = b; a; a--) {
dp[b + 1][i] = min(dp[b + 1][i], dp[a][b] + cost + s[i][a - 1] - s[b][a - 1]);
}
}
}
ll ans = llf;
for (int i = 1; i <= n; i++)
ans = min(ans, dp[i][n]);
printf("%lld\n", ans);
return 0;
}

Problem E ABC String

  先将连续的字符缩起来,设出现的次数满足 $a \leqslant b \leqslant c$。

  现在我们希望删掉一些 $a$ 使得存在一种方案使得删掉一些 $b, c$ 使得 $a = b = c$。

  不难发现,删掉一个 A 后至多使 $b$ 或 $c$ 减少 1。因此 A 仍然是出现次数最少的字符。

  假设删除一些 A 之后,仍然满足 $b \leqslant c$。

  如果 $b = c$,那么每次删掉 BC 或者 CB 就行了。

  考虑 $b - c$ 所能到达的最小值,如果一段中含 B,那么可以贡献 -1,如果只有一个 C,那么会贡献 1。

  因此,我们希望删掉一些 A,使得 $b - c$ 的最小值能小于等于 0。

  不难发现,只用删掉若干个单独的 C 之前的 A,并且删掉一个 A 至多使单独的 C 减少 1 个。

Code

#include<bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 1e6 + 5; int n;
char s[N], s1[N]; void shrink() {
int t = 0;
for (int i = 1; i <= n; i++) {
if (s[i] ^ s[i - 1]) {
s[++t] = s[i];
}
}
n = t;
} int cnt[3];
char pg[3], qg[3];
void trans() {
for (int i = 1; i <= n; i++) {
cnt[s[i] - 'A']++;
}
vector<pair<int, int>> a;
a.emplace_back(cnt[0], 0);
a.emplace_back(cnt[1], 1);
a.emplace_back(cnt[2], 2);
sort(a.begin(), a.end());
#define make_trans(x, y) pg[x] = y, qg[y] = x;
for (int i = 0; i < 3; i++)
make_trans(a[i].second, i);
for (int i = 1; i <= n; i++) {
s[i] = pg[s[i] - 'A'] + 'A';
}
} void make_valid() {
int x = 0, y = 0;
auto count = [&] (int l, int r) -> boolean {
if (l > r) return false;
for (int i = l; i <= r; i++) {
if (s[i] == 'B') {
x++;
return false;
}
}
if (l == 1 || r == n)
return false;
y++;
return true;
};
int ls = 0;
vector<int> pos;
for (int i = 1; i <= n; i++) {
if (s[i] == 'A') {
if (count(ls + 1, i - 1) && ls) {
pos.push_back(i);
}
ls = i;
}
}
count(ls + 1, n);
if (x < y) {
int t = 0;
pos.resize(y - x);
reverse(pos.begin(), pos.end());
for (int i = 1; i <= n; i++) {
if (!pos.empty() && i == pos.back()) {
pos.pop_back();
} else {
s[++t] = s[i];
}
}
n = t;
shrink();
s[n + 1] = 0;
}
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++)
cnt[s[i] - 'A']++;
int d = cnt[2] - cnt[1];
int t = 0;
char target = 'C';
(d < 0) && (d = -d, target = 'B');
ls = 0;
auto remove = [&] (int l, int r) {
if (l > r)
return;
if ((l == 1 || r == n) || (l ^ r)) {
if (s[l] == target && d) l++, d--;
if (l < r && s[r] == target && d) r--, d--;
}
for (int i = l; i <= r; i++)
s1[++t] = s[i];
};
for (int i = 1; i <= n; i++) {
if (s[i] == 'A') {
remove(ls + 1, i - 1);
s1[++t] = 'A';
ls = i;
}
}
remove(ls + 1, n);
n = t;
for (int i = 1; i <= n; i++) {
s[i] = s1[i];
}
s[n + 1] = 0;
} void make_equal() {
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++)
cnt[s[i] - 'A']++;
assert(cnt[1] == cnt[2]);
int d = cnt[1] - cnt[0];
int t = 0;
vector<pair<int, int>> pos;
for (int i = 1; i <= n; i++) {
if (i < n && d && s[i] != 'A' && s[i + 1] != 'A') {
if (s1[t] == 'A' && s[i + 2] == 'A') {
pos.emplace_back(t + 1, t + 2);
s1[++t] = s[i];
} else {
i++, d--;
}
} else {
s1[++t] = s[i];
}
}
n = t;
for (int i = 1; i <= n; i++)
s[i] = s1[i];
vector<int> delpos;
for (int i = 0; i < d; i++) {
delpos.push_back(pos[2 * i].first);
delpos.push_back(pos[2 * i + 1].second);
}
t = 0;
reverse(delpos.begin(), delpos.end());
for (int i = 1; i <= n; i++) {
if (!delpos.empty() && delpos.back() == i) {
delpos.pop_back();
} else {
s[++t] = s[i];
}
}
t = n;
assert(delpos.empty());
} int main() {
scanf("%s", s + 1);
n = strlen(s + 1);
shrink();
trans();
make_valid();
make_equal();
for (int i = 1; i <= n; i++)
s[i] = qg[s[i] - 'A'] + 'A';
s[n + 1] = 0;
puts(s + 1);
return 0;
}

Problem F Square Constraints

  考虑每个位置有一个上界 $R_i$ 和一个下界 $L_i$。对于后 $N$ 个位置下界为 0。

  考虑只有上界,我们把上界从小到大排序,那么答案等于 $\prod_{i = 0}^{2N - 1} (R_i - i)$。

  考虑对一些下界进行容斥。不难注意到下界非 0 的位置,它的上界是排在后 $N$ 个位置的上界之后。

  所以只用枚举一下有多少个数被硬点不合法就可以 dp 了。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define pii pair<int, int>
#define ll long long const int N = 505; int n, n2, Mod;
pii a[N];
int cnt[N];
int dp[2][N]; int main() {
scanf("%d%d", &n, &Mod);
n2 = n << 1;
int p1 = 0, p2 = 0, N4 = 4 * n * n, N2 = n * n;
for (int i = n2 - 1; ~i; i--) {
while (p1 < n2 && p1 * p1 <= N4 - i * i)
p1++;
while (p2 * p2 < N2 - i * i)
p2++;
if (p2) {
a[i] = pii(p2, p1);
} else {
a[i] = pii(p1, 0);
}
}
sort(a, a + n2);
cnt[0] = 0;
for (int i = 0; i < n2; i++)
cnt[i + 1] = cnt[i] + !a[i].second;
ll ans = 0;
for (int i = 0; i <= n; i++) {
int cur = 0;
memset(dp[0], 0, sizeof(dp[0]));
dp[0][0] = 1;
for (int j = 0; j < n2; j++) {
memset(dp[cur ^= 1], 0, sizeof(dp[0]));
for (int k = 0; k <= i; k++) {
if (!a[j].second) {
dp[cur][k] = (dp[cur][k] + 1ll * (a[j].first - k - cnt[j]) * dp[cur ^ 1][k]) % Mod;
} else {
dp[cur][k + 1] = (dp[cur][k + 1] - 1ll * (a[j].first - k - cnt[j]) * dp[cur ^ 1][k]) % Mod;
dp[cur][k] = (dp[cur][k] + 1ll * (a[j].second - (n + i + j - cnt[j] - k)) * dp[cur ^ 1][k]) % Mod;
}
}
}
ans += dp[cur][i];
}
ans %= Mod;
(ans < 0) && (ans += Mod);
printf("%d\n", (int) ans);
return 0;
}

AtCoder Grand Contest 036 简要题解的更多相关文章

  1. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

  2. AtCoder Grand Contest 039 简要题解

    从这里开始 比赛目录 Problem A Connection and Disconnection 简单讨论即可. Code #include <bits/stdc++.h> using ...

  3. AtCoder Grand Contest 040 简要题解

    从这里开始 比赛目录 A < B < E < D < C = F,心情简单.jpg. Problem A >< 把峰谷都设成 0. Code #include &l ...

  4. AtCoder Grand Contest 035 简要题解

    从这里开始 题目目录 Problem A XOR Circle 你发现,权值的循环节为 $a_0, a_1, a_0\oplus a_1$,然后暴力即可. Code #include <bits ...

  5. AtCoder Grand Contest 037 简要题解

    从这里开始 题目目录 Problem A Dividing a String 猜想每段长度不超过2.然后dp即可. 考虑最后一个长度大于等于3的一段,如果划成$1 + 2$会和后面相同,那么划成$2 ...

  6. AtCoder Grand Contest 038 简要题解

    从这里开始 比赛目录 Problem A 01 Matrix Code #include <bits/stdc++.h> using namespace std; typedef bool ...

  7. Atcoder Grand Contest 036 D - Negative Cycle

    Atcoder Grand Contest 036 D - Negative Cycle 解题思路 在某些情况下,给一张图加或删一些边要使图合法的题目要考虑到最短路的差分约束系统.这一题看似和最短路没 ...

  8. AtCoder Grand Contest 036题解

    传送门 爆炸的比较厉害--果然还是菜啊-- \(A\) 我们强制一个点为\((0,0)\),那么设剩下两个点分别为\((a,b),(c,d)\),根据叉积可以计算出面积为\(ad-bc=S\),那么令 ...

  9. AtCoder Grand Contest 021完整题解

    提示:如果公式挂了请多刷新几次,MathJex的公式渲染速度并不是那么理想. 总的来说,还是自己太弱了啊.只做了T1,还WA了两发.今天还有一场CodeForces,晚上0点qwq... 题解还是要好 ...

随机推荐

  1. go 1.13 环境变量配置

    GO111MODULE="off"GOARCH="amd64"GOBIN=""GOCACHE="/Users/js/Library ...

  2. RestController 能不能通过配置关闭

    https://stackoverflow.com/questions/29958231/can-a-spring-boot-restcontroller-be-enabled-disabled-us ...

  3. WPF ToggleButton Style

    <Style x:Key="ArrowToggleStyle" TargetType="ToggleButton"> <Setter Prop ...

  4. Elasticsearch PUT 插入数据

    { "error": { "root_cause": [ { "type": "illegal_argument_exceptio ...

  5. vue.js环境在window和linux安装

    一.windows环境下安装vue 1.node.js安装:在node.js的官网上下载node的安装包 https://nodejs.org/en/download/ 安装完毕之后,在命令行下验证是 ...

  6. Python基础17

    写出来的代码,若有部分不想运行,可注释掉. 看跑出来的结果,再加进来调试.

  7. Linux CentOS 下安装.net core sdk

    注册Microsoft密钥 sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm ...

  8. CTF必备技能丨Linux Pwn入门教程——栈溢出基础

    这是一套Linux Pwn入门教程系列,作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的一些题目和文章整理出一份相对完整的Linux Pwn教程. 课程回顾>>Linux ...

  9. 为什么我推荐你用 Ubuntu 开发?

    微信.QQ.TIM.企业微信.钉钉等 1.首先需要安装 wine 环境,这里使用到开源的 deepin-wine-ubuntu (项目地址: https://github.com/wszqkzqk/d ...

  10. Unity导出Gradle工程给Android Studio使用

    1 Unity导出Gradle项目 Unity打包时Build System选择Gradle,勾选Export Project 2 Android Studio导入Unity导出的Gradle项目 打 ...