B. osu!mania
按照題目的公式進行計算,注意四捨五入的精度問題。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using ldb = long double;
using vi = vector<int>;
using pii = pair<int,int>;
void solve(){
int ppmax;
cin >> ppmax;
int a, b, c, d, e, f;
cin >> a >> b >> c >> d >> e >> f;
ldb acc = (300.0 * a + 300 * b + 200 * c + 100 * d + 50 * e) / (300.0 *(a + b + c + d + e + f));
ldb tpp = (320.0 * a + 300 * b + 200 * c + 100 * d + 50 * e) * 5 * ppmax / (320.0 * (a + b + c + d + e + f));
i64 pp = max(0ll, i64(round(tpp)) - 4ll * ppmax);
cout <<fixed << setprecision(2) << acc*100.0 << "% " << pp << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}
C. 連方
如果第一行第七行都是#
,則全部都都是#
。
如果第一行第七行只有一行都是#
,則無解。
否則第二行、第六行對第一行、第七行取反,這樣可以把第一行和第七行所有#
都聯通。
然後再第三行第第五行各找一個之和第二行第六行八聯通的點,然後透過第四行聯通即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using ldb = long double;
using vi = vector<int>;
using pii = pair<int,int>;
void solve(){
int n;
cin >> n;
vector<string> a(7);
cin >> a[0] >> a[6];
bool f0 = false, f6 = false;
for(auto c : a[0])
f0 |= (c == '.');
for(auto c : a[6])
f6 |= (c == '.');
if(f0 != f6) {
cout << "No\n";
return;
}
cout << "Yes\n";
if(f0 == false) {
for(int i = 0; i < 7; i ++) cout << a[0] << "\n";
return;
}
for(int i = 1; i < 6; i ++) a[i] = string(n, '.');
for(int i = 0; i < n; i ++) if(a[0][i] == '.') a[1][i] = '#';
for(int i = 0; i < n; i ++) if(a[6][i] == '.') a[5][i] = '#';
int l = -1, r = -1;
for(int i = 0; i < n and l == -1; i ++) {
if(a[1][i] == '#') continue;
if(i - 1 >= 0 and a[1][i - 1] == '#') l = i;
if(i + 1 < n and a[1][i + 1] == '#') l = i;
}
for(int i = 0; i < n and r == -1; i ++) {
if(a[5][i] == '#') continue;
if(i - 1 >= 0 and a[5][i - 1] == '#') r = i;
if(i + 1 < n and a[5][i + 1] == '#') r = i;
}
a[2][l] = a[4][r] = '#';
if(l > r) swap(l, r);
if(l == r or l + 1 == r ){
a[3][l] = '#';
} else {
for(int i = l + 1; i < r ; i ++) a[3][i] = '#';
}
for(int i = 0; i < 7; i ++)
cout << a[i] << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}
D. 有限小數
對於一個分數,如果是有限小數。則分母質因數分解後一定只包含\(2,5\)。設\(w\)表示為\(b\)除了\(2,5\)外的質因子乘積。則\(d=2^x5^yw\)。找規律可以發現\(d\)一定滿足\(d=2^X5^Yw\)的形勢。因此有\(\frac a b + \frac c d = \frac{ad+cb}{bd}=k\)。我們要求的\(k\)一定是有限小數,則一定可以表示為\(k=\frac{z}{2^{x+X}5^{y+Y}},z\in \Z\)。因此我們只要解出丟番圖方程\(c\times b - z\times w ^2 = -a\times d\)的整數解,並求出\(c\)的最小正整數解即可。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const i64 MAXN = 1e9;
const i64 inf = LLONG_MAX / 2;
i64 exgcd(i64 a, i64 b, i64 &x, i64 &y) {
if(b == 0){
x = 1, y = 0;
return a;
}
i64 d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
i64 calc(i64 a, i64 b, i64 c) {
i64 x, y;
i64 d = exgcd(a, b, x, y);
if(c % d != 0) return inf;
x *= c / d;
i64 t = abs(b / d);
return (x % t + t) % t;
}
void solve() {
i64 a, b;
cin >> a >> b;
i64 w = b;
while(w % 2 == 0) w /= 2;
while(w % 5 == 0) w /= 5;
if(w == 1) {
cout << "0 1\n";
return;
}
i64 resc = inf, resd;
for(i64 p5 = w; p5 <= MAXN; p5 *= 5)
for(i64 d = p5, c; d <= MAXN; d *= 2) {
c = calc(b, w * w, - a * d);
if(c < resc) resc = c, resd = d;
}
cout << resc << " " << resd << "\n";
return;
}
int main() {
int T;
cin >> T;
while(T --)
solve();
return 0;
}
E. 合成大西瓜
對於度為\(1\)的點,只能是\(x,z\)。因此能儲存下的只有可能是次大值。否則,則可以是\(x,y,z\),一定可以儲存下最大值。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int,int>;
const int inf = INT_MAX / 2;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
vi a(n + 1);
for(int i = 1; i <= n; i ++) cin >> a[i];
vi deg(n + 1);
for(int x, y; m; m --) {
cin >> x >> y;
deg[x] ++, deg[y] ++;
}
int leaf1 = -inf, leaf2 = -inf, node = -inf;
for(int i = 1; i <= n; i ++) {
if(deg[i] == 1) {
if(a[i] > leaf1) leaf2 = leaf1, leaf1 = a[i];
else leaf2 = max(leaf2, a[i]);
}
else node = max(node, a[i]);
}
if(leaf2 == -inf) cout << node << "\n";
else if(node == -inf) cout << leaf2 << "\n";
else cout << max(node, leaf2);
return 0;
}
I. 算術
對於任意的兩個數\(x,y\),如果滿足\(1 < x,y\),則一定有\(xy \ge x + y\)。因為求和操作一定是至少有一個數為\(1\)。
這樣的話,考慮把卡牌分成若干組,每一組內求和,組之間求積。我們可以給每一組先分配一張卡牌,然後再給某些組進行加一。
因為一個組內不能有兩個大於一的數,因此組個數的變化實際上只受到了\(1\)的影響。因此我們可以列舉有多少個\(1\)作為一組。
然後我們考慮,如果\(x < y\),則一定有\((x + 1)y = xy + y > xy + x = x(y + 1)\)。因此加一操作應是對最小的組最優。我們用優先佇列維護每組的和,每次對最小的組加一即可。
考慮不同的分組方案如何比較,比較乘積無法實現,但是可以比較乘積的對數。
這樣的話,完全沒有分類討論。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int,int>;
const int mod = 998244353;
void solve() {
vi a(10);
for(int i = 1; i <= 9; i ++) cin >> a[i];
vi res;
ldb val = 0;
for(int i = 0; i <= a[1]; i ++) {
priority_queue<int,vi,greater<>> heap;
for(int j = 0; j < i; j ++)
heap.push(1);
for(int j = 2; j <= 9; j ++)
for(int k = 0; k < a[j]; k ++)
heap.push(j);
if(heap.empty()) continue;
int x = a[1] - i;
while(x --) {
int y = heap.top();
heap.pop();
heap.push(y + 1);
}
vi ret;
ldb ans = 0;
while(not heap.empty()) {
ret.push_back((i64)heap.top()), ans += log((i64)heap.top());
heap.pop();
}
if(ans > val) res = ret, val = ans;
}
int pi = 1;
for(auto i : res)
pi = pi * i % mod;
cout << pi << "\n";
return ;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}
J. 骰子
觀察題目,首先起始狀態底面為\(6\)。觀察樣例,樣例證明了存在一種方案可以使得右側第一格和下邊第一個底面為\(6\)。因此一定有一種方法可以使得每一格都是\(6\)。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int,int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
i64 n, m;
cin >> n >> m;
cout << n * m * 6ll << "\n";
return 0;
}
K. 小 C 的神秘圖形
觀察生成圖案的方法。如果座標的最高位都不是\(1\),則為\(0\)。否則可以遞迴詢問。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int,int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
string x, y;
cin >> x >> y;
ranges::reverse(x), ranges::reverse(y);
while(true){
if((x.back() == '1') or (y.back() == '1')) {
if(n == 1) {
cout << 1 << "\n";
return 0;
} else {
x.pop_back(), y.pop_back(), n --;
}
}else {
cout << 0 << "\n";
return 0;
}
}
return 0;
}