2024“图森未来杯”程序设计邀请赛
https://voj.mobi/contest/242/problems,密码2024ecnutsol
A - 调和与折中
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
i64 a, b, c, d, e, f;
cin >> a >> b >> c >> d >> e >> f;
if(f * (a * c + b) == c * (d * f + e)) cout << "Yes\n";
else cout << "No\n";
return 0;
}
B - 数位游戏
如果\(x<10\) 且为奇数,则无解。
否则记\(cnt=bitcnt(p)\),如果\(cnt\)为偶数,则一定存在一种不进位的方法,则答案为\(cnt/2\),否则存在一种只进一次位的方法,则答案为\(cnt/2+5\)
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
void solve(){
string s;
cin >> s;
if(s.size() < 2 and (s.front() - '0') % 2 == 1) {
cout << "-1\n";
return;
}
int cnt = 0;
for(auto i : s) cnt += i - '0';
if(cnt % 2 == 0) cout << cnt / 2 << "\n";
else cout << cnt / 2 + 5 << "\n";
return;
}
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int TC;
for(cin >> TC; TC; TC --)
solve();
return 0;
}
C - 抽卡与破防
根据题目可以得到出六星的概率
\[p(x) = \left\{\begin{matrix}
\frac {a}{100} & x \le n\\
\min(\frac{a + (x-n)b}{100},100)& x > n
\end{matrix}\right.
\]
然后可以得到不出六星的概率\(arcp(x) = 1 - p(x)\)
对于出六星是 up 的概率是\(q = \frac{c}{100}\),歪的概率是\(arcq = 1 - q\)
记\(E(i,j)\)表示从第\(i\)抽抽卡开始,累计\(j\)抽未出六星是,抽出\(up\)的概率是多少
对于没有到达保底的的情况\(i<m\)
\[E(i,j) = 1 + p(j) \times(arcq \times E(i+1,0) + q\times 0) + arcp[j] \times E(i+1,j+1)
\]
对于已经到达保底的情况\(i>m\)
\[E(i,j) = 1 + p(j) \times 0 + arcq(j)\times E(i + 1 , j + 1)
\]
然后我们递归加记忆化就可以的了,递归的过程中,如果已经到达保底出六星也就是\(arcq[j] = 0\)时就不要在搜索\(E(i+1,j+1)\)
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
const int N = 200, M = 20000, mod = 1e9+7;
int e[M + 1][N + 1], p[N + 1], arcp[N + 1];
int n, m, a, b, c, q, arcq;
int power(int x, int y) {
int ans = 1;
while(y) {
if(y & 1) ans = ans * x % mod;
x = x * x % mod;
y >>=1;
}
return ans;
}
int inv(int x) {
return power(x, mod - 2);
}
void init(){
int inv100 = inv(100);
q = c * inv100 % mod;
arcq = (100 - c) * inv100 % mod;
for(int x = 0; x <= N; x ++){
if(x <= n) p[x] = a * inv100 % mod;
else p[x] = min(a + (x - n) * b, 100ll) * inv100 % mod;
arcp[x] = (1ll - p[x] + mod) % mod;
}
for(int i = 0; i <= M; i ++)
for(int j = 0; j <= N; j ++)
e[i][j] = -1;
return;
}
int E(int i ,int j) {
if(e[i][j] != -1) return e[i][j];
if(i < m) {
e[i][j] = 1;
if(arcp[j] % mod != 0) e[i][j] = (e[i][j] + arcp[j] * E(i + 1, j + 1) % mod) % mod; // 没出六星
e[i][j] = (e[i][j] + p[j] * arcq % mod * E(i + 1 , 0) % mod ) % mod; // 出六星 但不是 up
} else { // 出六星必 up
e[i][j] = 1;
if(arcp[j] % mod != 0) e[i][j] = (e[i][j] + arcp[j] * E(i + 1, j + 1)) % mod; // 没出六星
}
assert(e[i][j] >= 0);
return e[i][j] %= mod;
}
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n >> m >> a >> b >> c;
init();
cout << E(0, 0);
return 0;
}
F - 花狮平衡树
想了很久,最后还是用裸的 splay树实现的。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using ll = long long;
using vi = vector<int>;
using pii = pair<int, int>;
const int N = 5e5+5;
int n;
struct Splay {
int rt, tot, fa[N], ch[N][2], val[N], cnt[N], siz[N];
int tag[N];
void push_up(int x) {
siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + cnt[x];
}
void push_down(int x) {
if (x && tag[x]) {
if (ch[x][0])tag[ch[x][0]] ^= 1;
if (ch[x][1])tag[ch[x][1]] ^= 1;
swap(ch[x][0], ch[x][1]);
tag[x] = 0;
}
}
bool get(int x) { return x == ch[fa[x]][1]; }
void clear(int x) {
ch[x][0] = ch[x][1] = fa[x] = val[x] = siz[x] = cnt[x] = 0;
}
void rotate(int x) {
int y = fa[x], z = fa[y], chk = get(x);
push_down(x);
push_down(y);
ch[y][chk] = ch[x][chk ^ 1];
if (ch[x][chk ^ 1]) fa[ch[x][chk ^ 1]] = y;
ch[x][chk ^ 1] = y;
fa[y] = x;
fa[x] = z;
if (z) ch[z][y == ch[z][1]] = x;
push_up(y);
}
void splay(int x, int goal) {
for (int f = fa[x]; (f = fa[x]) != goal; rotate(x))
if (fa[f] != goal) rotate(get(x) == get(f) ? f : x);
if (goal == 0)rt = x;
}
void splay(int x) {
splay(x, 0);
}
int kth(int k) {
int cur = rt;
while (1) {
push_down(cur);
if (ch[cur][0] && k <= siz[ch[cur][0]]) {
cur = ch[cur][0];
}
else {
k -= cnt[cur] + siz[ch[cur][0]];
if (k <= 0) {
splay(cur);
return cur;
}
cur = ch[cur][1];
}
}
}
int find(int x) {
return kth(x + 1);
}
int build(int L, int R, int father) {
if (L > R) { return 0; }
int x = ++tot;
int mid = (L + R) / 2;
fa[x] = father;
cnt[x] = 1;
val[x] = mid;
ch[x][0] = build(L, mid - 1, x);
ch[x][1] = build(mid + 1, R, x);
push_up(x);
return x;
}
void rev(int L, int R) {
int fl = find(L - 1);
int fr = find(R + 1);
splay(fl, 0);
splay(fr, fl);
int pos = ch[rt][1]; pos = ch[pos][0];
tag[pos] ^= 1;
}
void dfs(int x) {
push_down(x);
if (ch[x][0])dfs(ch[x][0]);
if (val[x] != 0 && val[x] != (n + 1))cout << val[x] << " ";
if (ch[x][1])dfs(ch[x][1]);
}
} tree;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int m;
cin >> n >> m;
tree.build(0, n + 1 , 0);
tree.rt = 1;
while(m -- ){
int l , r;
cin >> l >> r;
tree.rev(l ,r);
}
tree.dfs(tree.rt);
return 0;
}
H - 橡木蛋糕卷
首先我们计算出每个传送点到所有的蛋糕店的最短距离,然后就转换成了经典旅行商问题,用状压 dp 来解决。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using ll = long long;
using vi = vector<int>;
using pii = pair<int, int>;
const int N = (1 << 18) + 8;
int dx[] = {0,0,-1,1};
int dy[] = {1,-1,0,0};
int stos[20][20];
int dp[N][20];
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n,m;cin >> n >> m;
vector<vector<char>> a(n + 1,vector<char>(m + 1));
vector<pair<int,int>> t(1),s(1);
for (int i = 1;i <= n;i++){
for (int j = 1;j <= m;j++){
cin >> a[i][j];
if (a[i][j] == 'S') s.push_back({i,j});
if (a[i][j] == 'T') t.push_back({i,j});
}
}
auto bfs = [&](int sx,int sy)->vector<vector<int>>{
queue<pair<int,int>> q;
q.push({sx,sy});
vector<vector<int>> vis(n + 1,vector<int>(m + 1));
vector<vector<int>> d(n + 1,vector<int>(m + 1, 1e9));
d[sx][sy] = 0;
vis[sx][sy] = 1;
while (!q.empty()){
auto [x,y] = q.front();
q.pop();
for (int i = 0;i < 4;i++){
int u = x + dx[i],v = y + dy[i];
if (u < 1 || v < 1 || u > n || v > m || vis[u][v] || a[u][v] == '#'){
continue;
}
q.push({u,v});
d[u][v] = d[x][y] + 1;
vis[u][v] = 1;
}
}
return d;
};
int siz = s.size() - 1;
vector<int> ttos(s.size(),1e9);
int idx = 0;
for( int i = 0 ; i < 20 ; i ++ )
for( int j = 0 ; j < 20 ; j ++ )
stos[i][j] = 1e9;
for (int i = 1;i < s.size();i++){
auto [x,y] = s[i];
auto tmp = bfs(x,y);
for (int j = 1;j < s.size();j++){
auto [u,v] = s[j];
stos[i][j] = min(stos[i][j],tmp[u][v]);
}
for (auto [u,v] : t){
ttos[i] = min(ttos[i],tmp[u][v]);
}
}
for (int i = 1;i < (1 << siz);i++){
for (int j = 0;j < 20;j++){
dp[i][j] = 1e9;
}
}
dp[0][0] = 0;
for (int i = 1;i < (1 << siz);i++){
for (int j = 1;j <= siz;j++){
if ((i >> (j - 1)) & 1){ // END
int tmp = 1e9;
for (int k = 1;k <= siz;k++){ // ST
if ((i >> (k - 1) )& 1 && k != j){
tmp = min(tmp,dp[i - (1 << (j - 1))][k]);
dp[i][j] = min(dp[i][j],dp[i - (1 << (j - 1))][k] + stos[j][k]);
}
}
if (tmp == 1e9) tmp = 0;
dp[i][j] = min(dp[i][j],tmp + ttos[j]);
}
}
}
int ans = 1e9;
for (int i = 1;i <= siz;i++){
ans = min(dp[(1 << siz) - 1][i],ans) ;
}
cout << ans << endl;
return 0;
}