A. A+B问题
由于数据范围较小,所以直接从小到大枚举可能的 X X X进制,注意判断 X X X要大于题目中出现的最大值,若遇到符合题意的值就退出循环,时间复杂度 O ( 300 T ) O(300T) O(300T)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 2e6 + 10;
const int INF = 1e16;
const int mod = 1e9 + 7;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
string x, y, z;
cin >> x >> y >> z;
for(int i = 2;i <= 300;i++)
{
int ans = 0;
int t1 = 0, t2 = 0, t3 = 0;
int p;
for(auto c : x)
{
if(c >= '0' && c <= '9')
p = c - '0';
else
p = c - 'A' + 10;
ans = max(ans, p);
t1 = t1 * i + p;
}
for(auto c : y)
{
if(c >= '0' && c <= '9')
p = c - '0';
else
p = c - 'A' + 10;
ans = max(ans, p);
t2 = t2 * i + p;
}
for(auto c : z)
{
if(c >= '0' && c <= '9')
p = c - '0';
else
p = c - 'A' + 10;
ans = max(ans, p);
t3 = t3 * i + p;
}
if(t1 + t2 == t3 && ans < i)
{
cout << i << '\n';
return;
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
B. 看比赛
由于每次走的路都是选择最快的路,所以每一步一定都在某条最短路上
所以先用 d i j k s t r a dijkstra dijkstra正反都跑一遍最短路,如果 d 1 [ v ] + d 2 [ u ] + w = d 1 [ n ] d1[v] + d2[u] + w = d1[n] d1[v]+d2[u]+w=d1[n],说明 v v v和 u u u之间的路一定是最短路上的某一段,保留,通过这样的方法,我们可以删除除最短路外的其它路径,且重新构造的图为没有环的有向图
然后看如何取胜,如果某人已经到达了节点 u u u而且 u u u与 n n n相连,对这个人来说 u u u节点是他的必胜节点,所以我们从终点往起点走,如果 1 1 1节点有出现过 M M M的必胜态,则 M M M胜利,不然 I I I胜利,由于必胜态的相邻节点是必输态,所以用拓扑排序就能解决问题,时间复杂度 O ( n l o g m ) O(nlogm) O(nlogm)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const double eps = 1e-9;
const int N = 2e6 + 10;
const int INF = 1e16;
const int mod = 1e9 + 7;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
int n, m;
cin >> n >> m;
vector<array<int, 3>> edge;
vector<vector<pii>> e(n + 5);
for(int i = 1;i <= m;i++)
{
int u, v, w;
cin >> u >> v >> w;
edge.push_back({u, v, w});
e[u].push_back({v, w});
e[v].push_back({u, w});
}
auto dij = [&](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;
};
vector<int> d1, d2;
d1 = dij(1);
d2 = dij(n);
vector<vector<int>> ne(n + 5);
vector<int> cnt(n + 5), f(n + 5);
for(auto [u, v, w] : edge)
{
if(d1[v] + w + d2[u] == d1[n])
{
ne[u].push_back(v);
cnt[v]++;
}
if(d1[u] + w + d2[v] == d1[n])
{
ne[v].push_back(u);
cnt[u]++;
}
}
queue<int> q;
q.push(n);
while(!q.empty())
{
int fr = q.front();
q.pop();
for(auto u : ne[fr])
{
if(f[fr] == 0)
f[u] = 1;
cnt[u]--;
if(cnt[u] == 0)
q.push(u);
}
}
if(f[1] == 1)
cout << "Little M is the winner." << '\n';
else
cout << "Little I is the winner." << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
C. 方格染色
不是我说,这第一眼也太像状压 d p dp dp了(
由于任意两个黑色方格均不相邻,把一列看成整体,最后的答案中列的情况只有三种:白白,白黑,黑白
首先,我们把相邻列有黑块的列看作整体,例如:黑白,白黑,黑白或者白黑,黑白,白黑等等,剩下的列均为白白
黑块共有 k k k个,所以它能被分成 d ( 1 ≤ d ≤ m i n ( k , n − k + 1 ) ) d(1 \leq d \leq min(k,n-k+1)) d(1≤d≤min(k,n−k+1))个整体,对于某个 d d d,其实就是在 k − 1 k - 1 k−1个空位中选择 d − 1 d-1 d−1个空位插入隔板,所以共有 C ( k − 1 , d − 1 ) C(k-1,d-1) C(k−1,d−1)种
分为一个个整体之后,再考虑剩下的白白列,由于每个黑色列整体不能相邻(若相邻的话那就是一个整体),所以剩下要考虑的就是把一个个整体和白白列放在一起,要求每个黑块整体不相邻。白白列共有 n − k n - k n−k个,所以就是在 n − k + 1 n - k + 1 n−k+1个空位中选 d d d个空位放黑块整体,共有 C ( n − k + 1 , d ) C(n - k + 1, d) C(n−k+1,d)种
由于每个黑块整体都有两种状态,如长度为 3 3 3的黑块有黑白,白黑,黑白和白黑,黑白,白黑状态,所以 d d d个整体有 2 d 2^d 2d种情况
所以答案为 ∑ d = 1 m i n ( k , n − k + 1 ) C ( k − 1 , d − 1 ) ∗ C ( n − k + 1 , d ) ∗ 2 d \sum_{d = 1}^{min(k, n - k + 1)}C(k - 1, d - 1) * C(n - k + 1, d) * 2^d ∑d=1min(k,n−k+1)C(k−1,d−1)∗C(n−k+1,d)∗2d,注意答案取 m o d mod mod和 k = 0 k = 0 k=0和 n < k n<k n<k的特判,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const double eps = 1e-9;
const int N = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int fac[N], infac[N];
ll C(ll n,ll m){//n个数选m个数
return fac[n] * infac[n - m] % mod * infac[m] % mod;
}
inline ll binpow(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
res = res * a % mod;
a = (ll)a * a % mod;
b >>= 1;
}
return res;
}
void solve()
{
int n, k;
cin >> n >> k;
if(k == 0)
{
cout << "1" << '\n';
return;
}
if(n < k)
{
cout << "0" << '\n';
return;
}
int ans = 0;
for(int i = 1;i <= min(k, n - k + 1);i++) // 分几块
{
int t1 = C(k - 1, i - 1); // 把若干个黑色方格分成i块的分法
int t2 = C(n - k + 1, i); // 把i块分开
ans = (ans + t1 * t2 % mod * binpow(2, i) % mod) % mod;
}
cout << ans << '\n';
}
signed main()
{
fac[0] = 1;
infac[0] = 1;
for (int i = 1; i <= 1e6;i++){
fac[i] = i * fac[i - 1] % mod;
infac[i] = binpow(fac[i], mod - 2);
}
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}
E. 时间超限α
遍历每个评测机,小 M M M的代码在每个评测机 i i i的最大花费时间为 a [ i ] [ m i n ( k i , m ) ] a[i][min(k_i,m)] a[i][min(ki,m)],最后的答案就是所有的评测机最大花费时间的最大值,时间复杂度 O ( n ∑ k i ) O(n\sum{k_i}) O(n∑ki)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 2e6 + 10;
const int INF = 1e16;
const int mod = 1e9 + 7;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[2005][10005];
void solve()
{
int n;
cin >> n;
for(int i = 1;i <= n;i++)
{
cin >> a[i][1];
for(int j = 1;j <= a[i][1];j++)
cin >> a[i][j + 1];
}
int q;
cin >> q;
int ans = -1;
for(int i = 1;i <= n;i++)
{
if(q <= a[i][1])
ans = max(ans, a[i][q + 1]);
else
ans = max(ans, a[i][a[i][1] + 1]);
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
I. 期中考试
从起始日开始循环到结束日,如果当天不用加训则计数,时间复杂度 O ( 7000 ) O(7000) O(7000)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 2e6 + 10;
const int INF = 1e16;
const int mod = 1e9 + 7;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
int a, b, c;
cin >> a >> b >> c;
int t1, x, t2, y;
cin >> t1 >> x >> t2 >> y;
int cnt = 0;
while(1)
{
if(x != a && x != b && x != c)
cnt++;
x++;
if(x == 8)
{
x = 1;
t1++;
}
if(t1 == t2 && x == y)
break;
}
cout << cnt << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
L. 兄弟校问题
先把所有城市相同的学校放入并查集,由于题目中提到,关键词要完全一致地出现,所以可以把学校名通过下划线分成前部分关键词和后部分关键词。由于不区分大小写,所以统一将大写字母转成小写字母放入 s e t set set,每次询问关键词时,把两个都含有该关键词的学校放入并查集,时间复杂度 O ( 50 n m ) O(50nm) O(50nm)
#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const double eps = 1e-9;
const int N = 2e6 + 10;
const int INF = 1e16;
const int mod = 1e9 + 7;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
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];
}
};
string ct[1005];
vector<set<string>> un(1005);
void solve()
{
int n, m;
cin >> n >> m;
dsu d(n);
for(int i = 1;i <= n;i++)
{
string t;
cin >> t >> ct[i];
t += '_';
string now = "";
for(auto c : t)
{
if(c >= 'A' && c <= 'Z')
now += c - 'A' + 'a';
else if(c == '_')
{
//cout << now << '\n';
un[i].insert(now);
now = "";
}
else
now += c;
}
}
for(int i = 1;i <= n;i++)
{
for(int j = i + 1;j <= n;j++)
{
if(ct[i] == ct[j])
d.merge(i, j);
}
}
while(m--)
{
string qq;
cin >> qq;
string q;
for(auto c : qq)
{
if(c >= 'A' && c <= 'Z')
q += c - 'A' + 'a';
else
q += c;
}
for(int i = 1;i <= n;i++)
{
if(un[i].count(q))
{
for(int j = i + 1;j <= n;j++)
{
if(un[j].count(q))
d.merge(i, j);
}
break;
}
}
}
for(int i = 1;i <= n;i++)
cout << d.size(i) - 1 << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}