因为不会算法痛失Au :P
比去年进步了一点,模拟都写出来了而且一遍过。
“我要漂亮姐姐教我写代码”队,名字略抽象,师妹起的xD
补题链接:Dashboard - 2023年中国大学生程序设计竞赛女生专场 - Codeforces
面对样例编程(bushi
简单的想就是,其实最后的结果取决于第一局的结果,如果第一局胜利,则只要后面的全部平局即可胜利;若第一局输了,那后面的也只能是平局使得结果不会更差,所以只需要计算第一局胜利的概率即可,即1/n。
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int _ = 1;
// std::cin >> _;
while(_ --) {
int n, m;
std::cin >> n >> m;
std::cout << 1 << '/' << n << '\n';
}
return 0;
}
模拟,注意每次移动都是连同在当前被移动的棋子上面的棋子一起移动的。
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int _ = 1;
std::cin >> _;
while(_ --) {
std::vector<int> v[10];
v[2].push_back(1);
v[3].push_back(2);
v[4].push_back(3);
int mp[] = {0, 2, 3, 4};
mp[1] = 2, mp[2] = 3, mp[3] = 4;
for(int i = 1; i <= 12; i ++) {
int a, b, pos;
std::cin >> a >> b;
int now = mp[a];
int nex = now + b;
for(int j = 0; j < v[now].size(); j ++) {
if(v[now][j] == a) {
pos = j;
break;
}
}
for(int j = pos; j < v[now].size(); j ++) {
mp[v[now][j]] = nex;
v[nex].push_back(v[now][j]);
}
int len = v[now].size();
for(int j = pos; j < len; j ++)
v[now].pop_back();
}
std::cout << (v[9].size() == 3 ? "Y" : "N") << '\n';
}
return 0;
}
DFS枚举每种情况,分别计算取最大值即可,时间复杂度O(m*9^6),大概5e7,可以过。
#include <bits/stdc++.h>
typedef long long ll;
const int N = 105;
int a[15];
struct node {
int i, j, op;
ll a, b, d, v;
} e[N];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int _ = 1, n, m, k;
ll ans = 0;
// std::cin >> _;
std::function<void(int)> DFS = [&](int u) {
if(u == n + 1) {
ll res = 0;
for(int i = 1; i <= m; i ++) {
if(!e[i].op)
res += (e[i].a * a[e[i].i] + e[i].b * a[e[i].j] <= e[i].d ? e[i].v : 0);
else
res += (e[i].a * a[e[i].i] + e[i].b * a[e[i].j] >= e[i].d ? e[i].v : 0);
}
ans = std::max(ans, res);
return;
}
for(int i = 0; i <= k; i ++) {
a[u] = i;
DFS(u + 1);
}
};
while(_ --) {
std::cin >> n >> m >> k;
for(int l = 1; l <= m; l ++) {
int i, j, op, a, b, d, v;
std::cin >> i >> j >> op >> a >> b >> d >> v;
e[l] = {i, j, op, a, b, d, v};
}
DFS(1);
std::cout << ans << '\n';
}
return 0;
}
从1开始按位置倒着赋值,从LIS长度递增的顺序赋值,例如样例:1 2 2 3 3,那就赋值为1 3 2 5 4,模拟这个赋值过程即可。
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int _ = 1;
// std::cin >> _;
while(_ --) {
int n, max = 0;
std::cin >> n;
std::vector<int> a(n + 1), cnt[n + 1], ans(n + 1);
bool flag = true;
for(int i = 1; i <= n; i ++) {
std::cin >> a[i];
if(a[i] > max + 1)
flag = false;
else
max = std::max(max, a[i]);
cnt[a[i]].push_back(i);
}
if(!flag) {
std::cout << -1 << '\n';
continue;
}
int num = 1;
for(int i = 1; i <= n; i ++) {
for(int j = cnt[i].size() - 1; j >= 0; j --) {
ans[cnt[i][j]] = num ++;
}
if(cnt[i].empty()) break;
}
for(int i = 1; i <= n; i ++)
std::cout << ans[i] << " \n"[i == n];
}
return 0;
}
没那么大的模拟,我是用的队列模拟,每次模拟一回合的对战。
#include <bits/stdc++.h>
const int N = 1e5 + 5;
int h1[N], a1[N], b1[N], c1[N], d1[N], e1[N], w1[N], ea[N];
int h2[N], a2[N], b2[N], c2[N], d2[N], e2[N], w2[N], eb[N];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n, m, k;
std::cin >> n >> m >> k;
std::queue<int> A, B;
for(int i = 1; i <= n; i ++) {
std::cin >> h1[i] >> a1[i] >> b1[i] >> c1[i] >> d1[i] >> e1[i] >> w1[i];
A.push(i);
}
for(int i = 1; i <= m; i ++) {
std::cin >> h2[i] >> a2[i] >> b2[i] >> c2[i] >> d2[i] >> e2[i] >> w2[i];
B.push(i);
}
int cnt = 0;
int nowa, nowb;
while(!A.empty() && !B.empty() && cnt < k) {
nowa = A.front();
nowb = B.front();
A.pop();
B.pop();
int p = std::max(0, a1[nowa] - c2[nowb]);
int ma = std::max(0, b1[nowa] - d2[nowb]);
int ww = 0;
if(ea[nowa] >= e1[nowa])
ww = w1[nowa];
int hurt = std::max({p, ma, ww});
if(p == hurt) {
ea[nowa] ++;
h2[nowb] -= p;
}
else if(ma == hurt) {
ea[nowa] ++;
h2[nowb] -= ma;
}
else {
ea[nowa] -= e1[nowa];
h2[nowb] -= ww;
}
A.push(nowa);
nowa = A.front();
if(h2[nowb] <= 0) {
if(!B.empty()) {
nowb = B.front();
B.pop();
}
else break;
}
p = std::max(0, a2[nowb] - c1[nowa]);
ma = std::max(0, b2[nowb] - d1[nowa]);
ww = 0;
if(eb[nowb] >= e2[nowb])
ww = w2[nowb];
hurt = std::max({p, ma, ww});
if(p == hurt) {
eb[nowb] ++;
h1[nowa] -= p;
}
else if(ma == hurt) {
eb[nowb] ++;
h1[nowa] -= ma;
}
else {
eb[nowb] -= e2[nowb];
h1[nowa] -= ww;
}
B.push(nowb);
if(h1[nowa] <= 0) A.pop();
cnt ++;
}
if(!A.empty() && !B.empty())
std::cout << "Draw" << '\n';
else if(!A.empty())
std::cout << "Alice" << '\n';
else
std::cout << "Bob" << '\n';
return 0;
}
ps:我是会写答辩的xD
考虑对于A的字符串集合建立AC自动机,然后对于每个B给出的字符串枚举前缀,对于这些前缀,我们就可以在AC自动机上不断跳fail边得到可以匹配的后缀,并且是不重不漏的,这样就可以对于每一种匹配情况计算方案数。
在写代码时,其实对于AC自动机的板子对于统计答案的solve函数进行修改即可,每次从当前前缀到达的now点匹配的后缀去跳fail边,但是由于AC自动机的板子是在使用之后就被修改了,我在这里的做法是将它记录下修改的点,再给它复原即可。
#include <bits/stdc++.h>
typedef long long ll;
typedef std::pair<int, int> PII;
const int N = 5e5 + 5;
const int mod = 1e9 + 7;
struct AC_Automation {
int tr[N][26];
int fail[N];
ll dep[N];
int vis[N];
int cnt;
std::queue<int> q;
void init() {
cnt = 0;
memset(tr, 0, sizeof(tr));
memset(dep, 0, sizeof(dep));
memset(fail, 0, sizeof(fail));
memset(vis, 0, sizeof(vis));
while(!q.empty()) q.pop();
}
void insert(std::string s) {
int len = s.length();
int now = 0;
for(int i = 0; i < len; i ++) {
int v = s[i] - 'a';
if(!tr[now][v]) {
cnt ++;
tr[now][v] = cnt;
dep[cnt] = i + 1;
}
now = tr[now][v];
}
vis[now] ++;
}
void build() {
for(int i = 0; i < 26; i ++) {
if(tr[0][i]) {
fail[tr[0][i]] = 0;
q.push(tr[0][i]);
}
}
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = 0; i < 26; i ++) {
if(tr[u][i]) {
fail[tr[u][i]] = tr[fail[u]][i];
q.push(tr[u][i]);
}
else
tr[u][i] = tr[fail[u]][i];
}
}
}
int solve(ll ans, int now, ll pos, ll l) {
std::vector<PII> rec;
for(int i = now; i && ~vis[i]; i = fail[i]) {
rec.push_back({i, vis[i]});
ll res = vis[i] * ((pos + 2 - dep[i]) % mod * (l - pos) % mod) % mod;
ans = (ans % mod + res) % mod;
vis[i] = -1;
}
for(auto [x, y] : rec)
vis[x] = y;
return ans;
}
} AC;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int _ = 1;
// std::cin >> _;
while(_ --) {
int n, m;
std::cin >> n >> m;
for(int i = 1; i <= n; i ++) {
std::string s;
std::cin >> s;
AC.insert(s);
}
AC.build();
for(int i = 1; i <= m; i ++) {
std::string p;
std::cin >> p;
ll ans = 0;
int now = 0;
for(int j = 0; j < p.length(); j ++) {
now = AC.tr[now][p[j] - 'a'];
ans = AC.solve(ans, now, j, p.length());
}
std::cout << ans << '\n';
}
}
return 0;
}
ps:自己学了三天AC自动机写出来的题,AC的时候还是很开心的,可恶,为什么之前没学AC自动机呀!
待补
待补