[PA 2019] Desant & 饺子(zongzi)
感觉还是过于牛了,连着两次用意想不到的方式 A 题。
没事干就记一下。可能主要记下赛时怎么想的。
[PA 2019] Desant
做这题的时候感觉冥冥之中自有天意。
模拟赛是
有简单的
不优化第二维,这个 DP 就没前途了。一般做到这我可能就停了,但当时我没啥思考过程的就直接想到怎么设计状态了,不过赛时没仔细思考复杂度,只是单纯想多过几个包,没想到是正解。
这里属于马后炮,因为我根本就不是这么想的。 考虑平常求逆序对个数是怎么做的,大概就是枚举一维,另一位偏序,可能会用一个关于值域的数据结构维护。启发我们关于值域做文章。发现我们只在乎和之后元素的大小关系,那就设计出了状态:设
解释下这个
转移:设
实现的时候可以把这个
分析下赛时不会的复杂度:前
证明:
- 积最大的时候这些数相等,这个是小学数学。设这个数为
,那么积 。 取任意值都不影响最值的位置,取对数 。对这个式子求导,算出 的时候有最大值。于是 。
赛时的代码实现比较劣,当时用 gp_hash_table
测了下
总复杂度
// 赛时代码
#include <bits/stdc++.h>
using namespace std;
#define IL inline
#define vec vector
#define eb emplace_back
#define bg begin
#define emp emplace
#define fi first
#define se second
#define bg begin
#define al(v) v.bg(), v.end()
#define sz size
#define pp pop_back
#define lb lower_bound
#define ub upper_bound
#define mkp make_pair
#define exg exchange
using ubt = long long;
using uubt = unsigned long long;
using dub = double;
using pii = pair<int, ubt>;
auto ckx = [](auto &x, const auto &y) { (x < y) && (x = y); };
auto ckm = [](auto &x, const auto &y) { (x > y) && (x = y); };
template <typename T = int>
IL T _R() {
T s = 0, w = 1;
char c = getchar();
while (!isdigit(c)) w = c == '-' ? -1 : 1, c = getchar();
while (isdigit(c)) s = s * 10 + c - 48, c = getchar();
return s * w;
}
const int inf = 1e9;
const int N = 35;
const int maxN = N + 3;
int n, a[maxN];
int b[maxN][maxN];
int cnt[2];
vec<vec<int>> t[2];
vec<pii> f[2];
auto upd = [](auto &A, const auto &B) {
if (A.fi == B.fi) A.se += B.se;
else if (A.fi > B.fi) A = B;
};
const int mod = 1e7 + 73317;
const ubt B = 1231;
const uubt BB = 13331;
auto Tr = [](const auto &A) {
int S = 0;
uubt SS = 0;
for (auto i : A) {
S = S * B % mod + i;
if (S >= mod) S -= mod;
SS = SS * BB + i;
}
return mkp(S, SS);
};
struct HASH {
vec<int> T;
int head[mod], tot;
struct edge {
int ls;
uubt v;
int hs;
} e[1000000];
IL int find(int A, uubt B) {
for (int i = head[A]; i; i = e[i].ls)
if (e[i].v == B) return e[i].hs;
return -1;
}
IL void add(int A, uubt B, int V) {
if (head[A] == 0) T.eb(A);
e[++tot] = {head[A], B, V};
head[A] = tot;
}
IL void clear() {
for (int i : T) head[i] = 0;
T.clear();
tot = 0;
}
} mp[2];
auto id = [](int i, const auto &A) {
auto tmp = Tr(A);
auto v = mp[i].find(tmp.fi, tmp.se);
if (v != -1) return v;
v = cnt[i]++;
mp[i].add(tmp.fi, tmp.se, v);
f[i].eb(inf, 0), t[i].eb(A);
return v;
};
pii ans[maxN];
int main() {
freopen("des.in", "r", stdin);
freopen("des.out", "w", stdout);
// dub ST = clock();
n = _R();
for (int i = 1; i <= n; i++) a[i] = _R();
for (int i = n; i >= 1; i--) {
for (int j = i; j <= n; j++)
b[i][j] = a[j];
sort(b[i] + i, b[i] + n + 1);
b[i][i - 1] = 0, b[i][n + 1] = n + 1;
}
auto tmp = vec<int> (n + 1, 0);
upd(f[0][id(0, tmp)], mkp(0, 1));
int cur = 0;
for (int i = 1; i <= n; i++) {
cur ^= 1;
for (int j = 0; j < cnt[cur ^ 1]; j++) {
const auto &u = t[cur ^ 1][j];
vec<int> v, h;
int K = f[cur ^ 1][j].fi;
for (int p = i, fl = 0; p <= n + 1; p++)
if (a[i] == b[i][p]) {
v.eb(u[p - i] + u[p - i + 1]);
h.eb(u[p - i] + u[p - i + 1] + 1);
K += u[p - i + 1];
p++, fl = 1;
} else {
v.eb(u[p - i]), h.eb(u[p - i]);
if (fl) K += u[p - i];
}
int i1 = id(cur, v), i2 = id(cur, h);
upd(f[cur][i1], f[cur ^ 1][j]);
upd(f[cur][i2], mkp(K, f[cur ^ 1][j].se));
}
f[cur ^ 1].clear();
t[cur ^ 1].clear();
mp[cur ^ 1].clear();
cnt[cur ^ 1] = 0;
}
for (int i = 0; i < cnt[cur]; i++)
ans[t[cur][i][0]] = f[cur][i];
for (int i = 1; i <= n; i++)
printf("%d %lld\n", ans[i].fi, ans[i].se);
// dub ED = clock();
// cerr << (ED - ST) / 1e6 << endl;
}
饺子(zongzi)
非正解。
发现
我们想让限制尽可能松,可以拿众数当 “
然后对后面的数找就行了。做集合是难的,做区间是容易的,人类的大脑告诉我们:从小到大排序后比较容易找到答案。找不到怎么办,多随几遍。。。
复杂度
// 赛时代码。小改了下if的顺序
#include <bits/stdc++.h>
using namespace std;
#define int ubt
#define IL inline
#define vec vector
#define bstr basic_string
#define eb emplace_back
#define bg begin
#define emp emplace
#define fi first
#define se second
#define bg begin
#define al(v) v.bg(), v.end()
#define sz size
#define pp pop_back
#define mkp make_pair
#define lb lower_bound
#define ub upper_bound
#define exg exchange
using ubt = long long;
using uubt = unsigned long long;
using dub = double;
using pii = pair<int, int>;
auto ckx = [](auto &x, const auto &y) { (x < y) && (x = y); };
auto ckm = [](auto &x, const auto &y) { (x > y) && (x = y); };
template <typename T = int>
IL T _R() {
T s = 0, w = 1;
char c = getchar();
while (!isdigit(c)) w = c == '-' ? -1 : 1, c = getchar();
while (isdigit(c)) s = s * 10 + c - 48, c = getchar();
return s * w;
}
const int N = 3e5;
const int maxN = N * 2 + 3;
int n;
int b[maxN];
int tp;
pii a[maxN], c[maxN];
vec<int> pos;
int cnt[maxN];
deque<int> ls[maxN];
mt19937 rd(762);
signed main() {
freopen("zongzi.in", "r", stdin);
freopen("zongzi.out", "w", stdout);
n = _R();
for (int i = 1; i <= n * 2 - 1; i++)
cnt[b[i] = a[i].fi = _R()]++, a[i].se = i;
int mx = 0;
for (int i = 0; i < n; i++)
if (cnt[i] > cnt[mx]) mx = i;
for (int i = 1; i <= n * 2 - 1; i++)
if (a[i].fi != mx) {
c[++tp].fi = (a[i].fi - mx + n) % n;
c[tp].se = a[i].se;
} else pos.eb(a[i].se);
sort(c + 1, c + tp + 1);
if (pos.sz() >= n) {
while (n--)
printf("%lld ", pos.back()), pos.pp();
return 0;
}
do {
for (int i = 0; i < n; i++) ls[i].clear();
auto tmp = pos;
ls[0].eb(0);
for (int i = 1, j = 0; i <= tp; i++) {
j += c[i].fi, j %= n;
if (ls[j].sz()) {
while (ls[j].sz() && i - ls[j].front() > n) ls[j].pop_front();
if (ls[j].sz() && i - ls[j].front() + pos.sz() >= n) {
vec<int> ans;
for (int u = ls[j].front() + 1; u <= i; u++)
ans.eb(c[u].se);
while (ans.sz() < n) ans.eb(tmp.back()), tmp.pp();
for (auto u : ans) printf("%lld ", u);
puts("");
// j = 0;
// for (auto u : ans) j += b[u];
// cout << j % n << '\n';
return 0;
}
}
ls[j].eb(i);
}
} while (shuffle(c + 1, c + tp + 1, rd), 1);
puts("-1");
}
懒,而且我是 shadow,所以直接挂正解图片。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探