外校打星队伍,排名22/450,还算凑合吧。
A. A+B问题
直接枚举进制
#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
void solve() {
string str;
vi a, b, s;
cin >> str;
for (auto c: str) {
if (c >= '0' and c <= '9') a.push_back(c - '0');
else a.push_back(c - 'A' + 10);
}
cin >> str;
for (auto c: str) {
if (c >= '0' and c <= '9') b.push_back(c - '0');
else b.push_back(c - 'A' + 10);
}
cin >> str;
for (auto c: str) {
if (c >= '0' and c <= '9') s.push_back(c - '0');
else s.push_back(c - 'A' + 10);
}
auto f = [](vi a, int x) {
if (*max_element(a.begin(), a.end()) >= x) return -1;
int ans = 0;
for (auto i: a)
ans = ans * x + i;
return ans;
};
for (int i = 2, A, B, S; i <= 16; i++) {
A = f(a, i);
if (A == -1) continue;
B = f(b, i);
if (B == -1) continue;
S = f(s, i);
if (S == -1) continue;
if (S == A + B) {
cout << i << "\n";
return;
}
}
}
int main() {
int TC;
for (cin >> TC; TC; TC--)
solve();
return 0;
}
B. 看比赛
首先正反两遍最短路,这样就可以确定那些边一定是最短路上的边,删掉多余的方向和边就会形成一个有向无环图。
我们发现,在有向图上能一步到达 n 的点,对于这些点是先手必胜点。然后只能够走到先手必胜的点的点就是先手必败点,根据这个规律,我们把整张图反向,然后按照拓扑序根据这个规则去给点染色,最后判断 1 的属性即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using pii = pair<int, int>;
const int inf = 1e18;
void solve() {
int n, m;
cin >> n >> m;
vector<vector<pair<int, int>>> e(n + 1);
vector<vi> g(n + 1);
vector<array<int, 3>> edge(m);
for (auto &[u, v, w]: edge) {
cin >> u >> v >> w;
e[u].emplace_back(v, w);
e[v].emplace_back(u, w);
}
auto dij = [n, e](int x) {
vi dis(n + 1, inf);
vi vis(n + 1, 0);
dis[x] = 0ll;
priority_queue<pii, vector<pii>, greater<pii>> q;
q.emplace(0, x);
while (!q.empty()) {
auto [d, u] = q.top();
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto [v, w]: e[u]) {
if (dis[v] <= d + w)continue;
dis[v] = d + w;
q.emplace(dis[v], v);
}
}
return dis;
};
auto d1 = dij(1) , d2 = dij(n);
vi cnt(n+1) , f(n+1);
for( auto [ u , v , w ] : edge ){
if( d1[u] + w + d2[v] == d1[n] )
g[v].push_back(u) , cnt[u] ++;
else if ( d1[v] + w + d2[u] == d1[n] )
g[u].push_back(v) , cnt[v] ++;
}
queue<int> q;
q.push(n);
while( !q.empty() ){
int u = q.front();
q.pop();
for( auto v : g[u] ){
if( f[u] == 0 ) f[v] = 1;
cnt[v] --;
if( cnt[v] == 0 ) q.push(v);
}
}
if( f[1] ) cout << "Little M is the winner.\n";
else cout << "Little I is the winner.\n";
return ;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int TC;
for (cin >> TC; TC; TC--)
solve();
return 0;
}
C. 方格染色
#include <bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using pii = pair<int, int>;
const int inf = 1e18;
int32_t main() {
int n = 10, m = 10;
vector f(n + 1, vector(m + 1, vi(3, 0)));
f[0][0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= i; j++) {
for (int k = 0; k < 3; k++) {
if (j == 0 and k > 0) continue;
for (int l = 0; l < 3; l++) {
if ((l & k) != 0) continue;
if( j - (k > 0) == 0 and l != 0 ) continue;
f[i][j][k] += f[i - 1][j - (k > 0)][l];
}
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
cout << accumulate(f[i][j].begin(), f[i][j].end(), 0ll) << " ";
}
cout << "\n";
}
return 0;
}
首先我写了一个这样的 dp 去打表,然后对于\((n,k)\)的答案,发现当\(n<k\)时一定无解。
为了方便令\(n=n-k+1\),发现递推式子\(f(n,k)=\frac{2\times k\times f(n-1,k)}{n-1}+f(n-2,k),f(0,k)=0,f(1,k)=2\)
这样子我们自然可以得到一个\(O(nk)\)的递推,但是我发现\(\sum k \le 5\times10^5\),那么\(k\)的种类数最多就是\(1,2,3,\cdots\)这样取,也就是\(\frac{k(k-1)}{2}\le 5\times10^5\),\(k\)最多大约是\(10^3\)中,这样的话配合记忆化就可以实现复杂度控制在\(O(10^8)\)这样
#include <bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using pii = pair<int, int>;
const int inf = 1e18;
const int N = 1e5 + 5;
const int mod = 998244353;
vector<vector<int>> f(N);
vi inv(N);
int power( int x , int y ){
int ans = 1;
while( y ){
if( y & 1) ans = ans * x % mod;
x = x * x % mod , y /= 2;
}
return ans;
}
void solve() {
int n, k;
cin >> n >> k;
if (n < k) {
cout << "0\n";
} else if (k == 0) {
cout << "1\n";
} else {
int t = n - k + 1;
if (f[k].empty()) f[k].push_back(0), f[k].push_back(2);
for (int i = f[k].size() - 1; i <= t; i++)
f[k].push_back((2 * k % mod * f[k][i] % mod * inv[i] % mod + f[k][i - 1]) % mod);
cout << f[k][t] << "\n";
}
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
inv[0] = -1;
for( int i = 1 ; i < N ; i ++ ) inv[i] = power( i , mod-2);
int TC;
for (cin >> TC; TC; TC--)
solve();
return 0;
}
E. 时间超限α
就是求一下前缀的最大值就好了。
#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
int res = 0;
vector< vi > a(n+1);
for( int i = 1 , x ; i <= n ; i ++ ){
cin >> x;
a[i].resize( x + 1 );
for( int j = 1 ; j <= x ; j ++ ) cin >> a[i][j];
}
int m;
cin >> m;
for( int i = 1 ; i <= n ; i ++ ){
for( int j = 1 ; j <= min( m , (int)a[i].size()-1 ) ; j ++ )
res = max( res , a[i][j] );
}
cout << res << "\n";
return 0;
}
I. 期中考试
模拟一下就好了
#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
set<int> x;
for (int i = 1, v; i <= 3; i++)
cin >> v, x.insert(v);
int res = 0;
int a0, a1, b0, b1;
cin >> a0 >> a1 >> b0 >> b1;
if (a0 == b0) {
for (int i = a1; i < b1; i++) {
if (x.count(i) == 0) res++;
}
} else {
for (int i = a1; i <= 7; i++) {
if (x.count(i) == 0) res++;
}
for (int i = 1; i < b1; i++) {
if (x.count(i) == 0) res++;
}
int cnt = 0;
for (int i = 1; i <= 7; i++) {
if (x.count(i) == 0) cnt++;
}
for (int i = a0 + 1; i < b0; i++)
res += cnt;
}
cout << res << "\n";
return 0;
}
L. 兄弟校问题
首先兄弟学校之间的关系用并查集来维护就好了。
剩下就是如何判断兄弟学校,首先\(O(n^2)\)的根据城市判断一下。
然后再\(O(nm)\)的根据关键字判一下,因为这里面的字符串不太长,我直接截取下来,转成小写字母丢进 set 就好了。
#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
#define lowbit(x) ( x & - x )
struct dsu {
vi fa;
dsu(int n = 1){
fa = vi( n+1 , -1ll );
fa[0] = 0;
}
int getfa(int x) {
if (fa[x] < 0) return x;
return fa[x] = getfa(fa[x]);
}
void merge(int x, int y) {
x = getfa(x), y = getfa(y);
if (x == y) return;
if (fa[x] > fa[y]) swap(x, y);
fa[x] += fa[y], fa[y] = x;
}
int size(int x) {
x = getfa(x);
return -fa[x];
}
};
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
dsu d(n);
vector<set<string>> keyWords(n+1);
vector<string> city(n+1);
auto toLow = [](string s) {
for (auto &i: s)
if (i >= 'A' and i <= 'Z') i = i + 'a' - 'A';
return s;
};
for (int i = 1; i <= n; i++) {
string s , t = "";
cin >> s >> city[i];
s += '_';
for ( auto c: s) {
if (c == '_') {
keyWords[i].insert(toLow(t) );
t = "";
} else t += c;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
if (city[i] != city[j]) continue;
d.merge(i, j);
}
}
string key;
for (int i = 1, p, q; i <= m; i++) {
cin >> key;
for (p = 1; p <= n; p++)
if (keyWords[p].count(key)) break;
for (q = p + 1; q <= n; q++) {
if (keyWords[q].count(key)) d.merge(p, q);
}
}
for( int i = 1 ; i <= n ; i ++ )
cout << d.size(i) - 1 << "\n";
return 0;
}
- Programming University Contest Jimei Theprogramming university contest jimei programming university jiaotong contest university the stanford famous engineering programming collegiate university hong kong programming the contest programming beginner atcoder programming collegiate provincial contest the-c-programming-language-readin subregional programming acm-icpc contest programming collegiate jiangsu contest