PS:实际打了2两个小时左右,被叫走去干活了。所以就直接补题了

A

B

C

D

E

F

G

H

I

J

K

L

M




AC

AC


AC

AC

AC





C.​​Strange Matrices​​ 状压DP

待补

D. ​​Strange Fractions​​ 数学/暴力

题目分析

对于给定的The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#include,找到The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_02满足The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_03。找不到输出The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_算法_04

The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_05,则The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_06,故可得:The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_07,方程解为有理数时The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_08为有理数,则The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#include_09为完全平方数。那么对于是否有解只需判断The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_10即可。

Code

#include <bits/stdc++.h>
#define int long long
#define end '\n'
using namespace std;


inline void solve(){
int p, q; cin >> p >> q;
int res = pow(p * p - 4 * q * q, 0.5);
if(res * res == p * p - 4 * q * q){
int det = sqrt(p * p - 4 * q * q), a = 0, b = 2 * q;
if(det > p) a = p + det;
else a = p - det;
cout << a << ' ' << b << endl;
} else {
cout << "0 0\n";
}
}

signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
int t = 0; cin >> t;
while(t--) solve();
return 0;
}

E.​​Strange Integers​​ 暴力

题目分析

要求从原集合中选择若干个数字组成新集合,使得新集合中的两两数字之差大于The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_11

直接排序,然后贪心扫一遍即可。

Code

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const int N = 1e5 + 10;
int a[N];

inline void solve(){
int n, k; cin >> n >> k;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n);
int pre = a[1], ans = 1;
for(int i = 2; i <= n; i++){
if(a[i] - pre >= k) ans++, pre = a[i];
}
cout << ans << endl;
}

signed main(){
solve();
return 0;
}

G.​​Edge Groups​​ 树形DP

题目分析

给定一棵树,要求对所有的边进行两两分组,每组满足必须两条边+两条边共顶点。

考虑对子树的答案进行统计:如果子节点的数目为偶数个,那么两两配对的方案数(定序)为:
The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_12
化简上式可得:
The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_13
如果子节点为奇数个,那么由于当前节点存在连向父节点的边,需要去除一条单独的边与连向父节点的边配对,因此此时连向父节点的边被占用。

Code

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const int N = 1e5 + 10, MOD = 998244353;

vector<int> g[N];

int n = 0;
int dp[N];

bool dfs(int u, int fa){
dp[u] = 1;
int cnt = 0;
for(auto v : g[u]){
if(v == fa) continue;
if(!dfs(v, u)) cnt++;
(dp[u] *= dp[v]) %= MOD;
}
for(int i = 1; i <= cnt; i += 2) (dp[u] *= i) %= MOD;
return cnt & 1;
}

inline void solve(){
cin >> n;
for(int i = 1; i < n; i++){
int u, v; cin >> u >> v;
g[u].emplace_back(v);
g[v].emplace_back(u);
}
dfs(1, -1);
cout << dp[1] << endl;
}

signed main(){
solve();
return 0;
}

H.​​Life is a Game​​ Kruskal重构树

题目分析

给定一张The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_算法_14个点The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_15条边的无向图,以及The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_16个询问。对于每个询问,给定初始点和初始经验值,经过一条边要求当前经验值大于边权,经过一个点后点权累加至经验值。求能够获得的最大经验。

首先容易证明,对于最终的答案,两个点之间的所有简单路径上最大边权的最小值 = 最小生成树上两个点之间的简单路径上的最大值 = The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_算法_17l 重构树上两点之间的 The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#include_18

那么容易想到对原图建The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_19重构树,不妨先对样例建树:

The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#include_20

红色数字表示The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_19重构树的点权,即为原图最大边权最小值。叶节点均为原图节点,黑色数字表示经验值,由于后期计算方便需要,将经验值自叶子节点向根节点求和。

那么我们对于某个询问,只需要从对应的叶节点开始往上跳到祖先节点,直至跳不过去(经验值小于点权(红色数字)),同时我们处理出了到达每个父节点能够获得的经验值(黑色数字),这样只需要一路往上跳检查是否满足经验值大于The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_19重构树的点权值就可以了。

Code

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const int N = 2e5 + 10;

int n, m, q;

int pnt[N], val[N];

struct unionfind{
int par[N];
unionfind(int n){ for(int i = 1; i <= n; i++) par[i] = i; }
int find(int x){ return x == par[x] ? x : (par[x] = find(par[x])); }
void merge(int u, int v){
int fau = find(u), fav = find(v);
if(fau != fav) par[fav] = fau;
}
int ismerge(int u, int v){ return find(u) == find(v); }
};

vector<int> g[N];

namespace KR{
struct edge{
int u, v ,w;
const bool operator< (const edge &x) const { return w < x.w; }
}edges[N];

inline void add_edge(int i, int u, int v, int w){ edges[i] = {u ,v, w}; }

int kruskal(){
int tot = n, cnt = 0;
unionfind uf(n + 20);
sort(edges + 1, edges + 1 + m);
for(int i = 1; i <= m; i++){
int nu = edges[i].u, nv = edges[i].v, nw = edges[i].w;
int fau = uf.find(nu), fav = uf.find(nv);
if(fau != fav){
val[++tot] = edges[i].w;
uf.par[tot] = uf.par[fau] = uf.par[fav] = tot;
g[fau].emplace_back(tot), g[fav].emplace_back(tot);
g[tot].emplace_back(fau), g[tot].emplace_back(fav);
cnt++;
}
if(cnt == n - 1) break;
}
return tot;
}
}

int fa[N][20];

void dfs0(int u, int ufa){
fa[u][0] = ufa;
for(int i = 1; i < 20; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];
for(auto v : g[u]){
if(v == ufa) continue;
dfs0(v, u);
pnt[u] += pnt[v];
}
}

using KR::add_edge;
using KR::kruskal;

inline void solve(){
cin >> n >> m >> q;
for(int i = 1; i <= n; i++) cin >> pnt[i];
for(int i = 1; i <= m; i++){
int u, v, w; cin >> u >> v >> w;
add_edge(i, u, v ,w);
}
n = kruskal();
dfs0(n, 0);
val[0] = 1e18;
while(q--){
int u, s; cin >> u >> s;
int ans = pnt[u] + s;
while(u != n){
int t = u;
for(int i = 19; i >= 0; i--)
if(val[fa[u][i]] <= ans) u = fa[u][i];
if(t == u) break;
ans = pnt[u] + s;
}
cout << ans << endl;
}
}

signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
solve();
return 0;
}

I.​​Steadily Growing Steam​​ 背包DP

题目分析

给定The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_算法_14个物品以及其体积和价值,每次最多选择The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_11个物品使其体积翻倍,然后选出若⼲物品并将其分为体积和 相同的两堆,问选出的物品价值之和最⼤是多少。

The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_25表示只考虑前The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_26张牌,还可以翻倍The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#include_27次,当前体积为The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_28的最大价值。

那么有转移方程:
The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_29
第一维可以滚动数组优化一下。

Code

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define ull unsigned long long
using namespace std;
int n, m;
const int N = 1e5 + 5;
int a[N], v[N], t[N];
int dp[105][5300][105];
int st = 2600, inf = 1e18;

void solve(){
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> v[i] >> t[i];

for (int i = 0; i <= n; i++){
for (int j = 0; j <= 5200; j++){
for (int k = 0; k <= m; k++) dp[i][j][k] = -inf;
}
dp[i][st][0] = 0;
}
for (int i = 1; i <= n; i++){
for (int j = 0; j <= 5200; j++){
for (int k = 0; k <= m; k++){
dp[i][j][k] = dp[i - 1][j][k];
if (j >= t[i])
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j - t[i]][k] + v[i]);
if (j + t[i] <= 5200)
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j + t[i]][k] + v[i]);
if (k && j >= 2 * t[i])
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j - 2 * t[i]][k - 1] + v[i]);
if (k && j + 2 * t[i] <= 5200)
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j + 2 * t[i]][k - 1] + v[i]);
}
}
}
int ans = -inf;
for (int i = 0; i <= m; i++) ans = max(ans, dp[n][st][i]);
cout << ans;
}

signed main(){
ios::sync_with_stdio(false), cin.tie(0);
int t = 1;
while (t--) solve();
return 0;
}

J.​​Two Binary Strings Problem​​ 位运算

题目分析

给定正整数The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_算法_14,以及两个长度为The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_算法_14的二进制串The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_算法_32The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_33。同时,定义函数:
The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_算法_34
如果The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_11满足对于任意The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_36,则The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_11为幸运数。对于每个The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#include_38中的数字判断是否为幸运数。

定义前缀和The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_39,那么The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_40表示The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_41的个数大于等于The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_42的个数。

首先按照前缀和大小进行排序,然后顺序遍历,我们可以发现,对于The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_43的情况一定The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_44不是The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_42(The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_算法_46表示The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_41的个数大于等于The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_42的个数),那么就把前面的出现过的位置全部标记掉。

如果The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_49那么就是直接或起来标记,否则需要对The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_深度优先_50取反后标记。另外注意对于The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_11长度以内的前缀也需要检验合法性,因此还要要维护一个合法范围标记。

Code

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const int N = 5e4 + 10;
int s[N], id[N];
bitset<N> A, ans, flip;


inline void solve(){
A.reset(), ans.reset(), flip.reset();
int n = 0; cin >> n;
string a, b; cin >> a >> b;
a = '@' + a, b = '@' + b;
for(int i = 1; i <= n; i++) flip.set(i);
id[0] = 0;
for(int i = 1; i <= n; i++){
s[i] = s[i - 1] + (a[i] == '1' ? 1 : -1);
id[i] = i;
}
sort(id, id + 1 + n, [](int x, int y){ return s[x] > s[y] || s[x] == s[y] && x < y; });
int tg = n + 1;
for(int i = 0; i <= n; i++){
int pos = id[i];
if(pos){
if(b[pos] == '1') {
ans = ans | (A >> (n - pos));
if(s[pos] <= 0) tg = min(tg, pos + 1);
} else {
ans = ans | ((A ^ flip) >> (n - pos));
if(s[pos] > 0) tg = min(tg, pos + 1);
}
}
A[n - pos] = 1;
}
for(int i = 1; i <= n; i++){
if(ans[i] || i >= tg) cout << 0;
else cout << 1;
}
cout << endl;
}

signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
int t = 0; cin >> t;
while(t--) solve();
return 0;
}

K.​​Circle of Life​​ 构造

题目分析

是给一个二进制串,每一次变换之后第The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_26The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_42会分裂成两个The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_42向左右两侧跑,如果两个分裂的撞在一起或碰到边界会消失,要求构造满足题意的串,使得在The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_i++_55次循环以内变出原始串。

由于相撞可以抵消,那么考虑是否存在循环节能够使原串被割裂为若干个独立块,从而各块独立循环。可以得到最小的循环节为The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#include_56,那么对于构造的串而言,只需要单独对剩余部分The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP_#define_57进行讨论就可以了。

Code

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const string biao[5] = {"1001", "10001", "100110", "1001010"};

inline void solve(){
int n = 0; cin >> n;
if(n == 2) cout << "10\n";
else if(n == 3) cout << "Unlucky\n";
else if(n == 4) cout << "1000\n";
else if(n <= 7) cout << biao[n - 4] << endl;
else{
for(int i = 1; i <= ((n - 4) / 4); i++) cout << biao[0];
cout << biao[(n - 4) % 4] << endl;
}
}

signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
solve();
return 0;
}

M.​​Harmony in Harmony​​ 结论/构造

题目分析

非常结论的题…

分析待补

Code

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const string biao[5] = {"1001", "10001", "100110", "1001010"};

inline void solve(){
double n = 0; cin >> n;
cout << 1 / (n * ((int)((n + 1) / 2)) * ((int)((n + 2) / 2))) << endl;
}

signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
cout << fixed << setprecision(9);
solve();
return 0;
}