第十六届蓝桥杯软件赛省赛C++ B组 题解。
A. 移动距离
首先不难发现一个简单的达到目的地的方案。
然后只需证明这个最简单的方案也是最优的就可以了。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | #include<bits/stdc++.h>#define int long long
 using namespace std;
 
 void solve(){
 double x = 233, y = 666;
 double l = sqrt(x * x + y * y);
 
 cout << fixed << setprecision(0);
 cout << l + l * atan2(y, x) << '\n';
 }
 
 signed main(){
 ios::sync_with_stdio(0);
 cin.tie(0);
 solve();
 return 0;
 }
 
 | 
B. 客流量上限
$$
A_i\ne 2025 (i\le 2024)\leftarrow A_i^2\le i^2+2025
$$
于是 $A_{2025}=2025$.
$$
A_i\ne 2024 (i\le 2023)\leftarrow A_i^2\le i^2+2025
$$
于是 $A_{2024}=2024$.
….
重复此过程,右侧能推得左侧的条件是:
$$
(t+1)^2>t^2+2025\rightarrow t> 1012
$$
所以 $A_i=i\ (i\ge 1013)$。
接下来,令 $A_j=2025$,推得 $A_i\times2025\le A_i\times2025+2025$,即 $A_i\le i+1\ (i\le 1012)$。
最后证明  $A_i=i\ (i\ge 1013)$,$A_i\le i+1\ (i\le 1012)$ 也是满足题设的充分条件即可。
分为三种情况讨论:
- $i,j\le 1012$,$A_iA_j\le(i+1)(j+1)=ij+i+j+1\le ij+2025$,满足。
- $i\le1012,j\ge1013$,$A_iA_j\le(i+1)j\le ij+j\le ij+2025$,满足。
- $i,j\ge 1013$,$A_iA_j\le ij\le ij+2025$,满足。
所以:
$A_1$ 可取 1,2
$A_2$ 可取 1,2,3
$A_3$ 可取 1,2,3,4
…
$A_{1012}$ 可取 1,2,3,4,…,1013
每个数都有两种选择(在前面的数选完的基础上)。
所以答案为 $2^{1012} (mod\ 1e9+7)$。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | #include<bits/stdc++.h>#define int long long
 using namespace std;
 
 constexpr int mod = 1e9 + 7;
 
 int qmi(int a, int k, int p){
 int res = 1;
 while(k){
 if(k & 1) res = res * a % p;
 a = a * a % p;
 k >>= 1;
 }
 return res;
 }
 
 void solve(){
 cout << qmi(2, 1012, mod) << '\n';
 }
 
 signed main(){
 ios::sync_with_stdio(0);
 cin.tie(0);
 solve();
 return 0;
 }
 
 | 
C. 可分解的正整数
类似一个构造题,可以发现,任何大于 1 的数 $n$ 都可以被表示为 :
$$
-(n-1),-(n-2),…,n-2,n-1,n
$$
且序列长度至少有 3,只有 1 无法被三个连续递增的整数表示。
输出非 1 的个数即可。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | #include<bits/stdc++.h>#define int long long
 using namespace std;
 
 void solve(){
 int n; cin >> n;
 
 int res = 0;
 while(n--){
 int x; cin >> x;
 res += x != 1;
 }
 
 cout << res << '\n';
 }
 
 signed main(){
 ios::sync_with_stdio(0);
 cin.tie(0);
 solve();
 return 0;
 }
 
 | 
D. 产值调整
第一眼看似乎没有很好的优化方法,但细看发现,三个数的差值基本在以一个 $\log$ 的速度收敛,所以直接模拟该过程,知道三个数相等为止。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | #include<bits/stdc++.h>#define int long long
 using namespace std;
 
 void solve(){
 int a, b, c, k; cin >> a >> b >> c >> k;
 
 for(int i = 0; i < k; i++){
 int u = b + c >> 1;
 int v = a + c >> 1;
 int w = a + b >> 1;
 a = u, b = v, c = w;
 if(a == b && b == c) break;
 }
 
 cout << a << ' ' << b << ' ' << c << '\n';
 }
 
 signed main(){
 ios::sync_with_stdio(0);
 cin.tie(0);
 int t; cin >> t;
 while(t--) solve();
 return 0;
 }
 
 | 
E. 画展布置
显然排序后取连续的一段可以让答案最优,找出最优的一段即可。
(排序后,求和的结果可以将绝对值打开,最后就是 $B_M^2-B_1^2$ 即可)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | #include<bits/stdc++.h>#define int long long
 using namespace std;
 
 void solve(){
 int n, m; cin >> n >> m;
 vector<int> a(n);
 for(auto &i : a) cin >> i;
 
 sort(a.begin(), a.end());
 
 int res = 1e18;
 for(int i = 0; i + m - 1 < n; i++){
 res = min(res, a[i + m - 1] * a[i + m - 1] - a[i] * a[i]);
 }
 
 cout << res << '\n';
 }
 
 signed main(){
 ios::sync_with_stdio(0);
 cin.tie(0);
 solve();
 return 0;
 }
 
 | 
F. 水质检测
先想出最优的方案,然后模拟你想出来的方案即可。
写了一个小状压,将每一列压成一个状态,从第一次找到 # 开始,准备填充。
进入准备填充状态后,每次遇到新的 #,找一个最优的填充方案,然后将 last 状态更新即可。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
 | #include<bits/stdc++.h>#define int long long
 using namespace std;
 
 void solve(){
 string a, b; cin >> a >> b;
 int n = a.size();
 
 vector<int> dp(n);
 for(int i = 0; i < n; i++){
 dp[i] = (a[i] == '#') + (b[i] == '#') * 2;
 }
 
 int fd = 0, last = 0, pos = 0, res = 0;
 for(int i = 0; i < n; i++){
 if(!dp[i]) continue;
 
 if(!fd){
 fd = 1;
 last = dp[i];
 }
 else{
 if(last & dp[i]){
 res += i - pos - 1;
 last = dp[i];
 }
 else{
 res += i - pos;
 last = 3;
 }
 }
 
 pos = i;
 }
 
 cout << res << '\n';
 }
 
 signed main(){
 ios::sync_with_stdio(0);
 cin.tie(0);
 solve();
 return 0;
 }
 
 | 
G. 生产车间
实质是,每次用子节点可达的数去更新父节点可达的数。
每次更新是一个卷积的过程,子节点可达 $a_i$,父节点可达 $b_i$,那么更新后所有可达的值为 $a_i+b_j$ 的所有组合。(所以有大佬用 fft 实现可以达到 $O(n\log n)$)
当然,我们用一个 bitset 优化基本时间就够了。更新过程用移位加速,更新完保留低 w[u] 位的值。
最后看根节点的最大可达值即可。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 
 | #include<bits/stdc++.h>#define int long long
 using namespace std;
 
 void solve(){
 int n; cin >> n;
 vector<int> w(n);
 for(auto &i : w) cin >> i;
 
 vector<vector<int>> adj(n);
 for(int i = 1; i < n; i++){
 int u, v; cin >> u >> v;
 u--, v--;
 adj[u].emplace_back(v);
 adj[v].emplace_back(u);
 }
 
 vector<bitset<1001>> dp(n);
 function<void(int, int)> dfs = [&](int u, int fa){
 dp[u][0] = 1;
 if(u && adj[u].size() == 1){
 dp[u][w[u]] = 1;
 return;
 }
 
 bitset<1001> tmp;
 tmp[0] = 1;
 for(auto &v : adj[u]){
 if(v == fa) continue;
 dfs(v, u);
 for(int i = 0; i < 1001; i++){
 if(dp[u][i]){
 tmp |= dp[v] << i;
 }
 }
 swap(dp[u], tmp);
 }
 
 dp[u] <<= (1000 - w[u]);
 dp[u] >>= (1000 - w[u]);
 };
 dfs(0, -1);
 
 int res = 0;
 for(int i = w[0]; i >= 0; i--){
 if(dp[0][i]){
 res = i;
 break;
 }
 }
 
 cout << res << '\n';
 }
 
 signed main(){
 ios::sync_with_stdio(0);
 cin.tie(0);
 solve();
 return 0;
 }
 
 | 
H. 装修报价
观察这么一个随意的式子:
$$
a+b\oplus c-d+e
$$
我们很容易找出其对偶(我们暂且这么称呼):
$$
a-b\oplus c+d-e
$$
此两者的和为 $2a$,不妨记每一个的贡献为 $a$ 好了。
不难发现所有的式子都可以如此配对,有的贡献为 $a$,有的贡献为 $a\oplus b$,…
动手模拟一下就可以看出,这些贡献都是这个序列的异或前缀,我们只需计算出每个异或前缀出现的次数就好了。
对于贡献为 $a$ 的,紧跟其后的符号有 + - 两个选择,其余符号任意,因此出现$2\times 3^{n-2}$ 次,对于贡献为 $a\oplus b$ 的,类似分析下去 …
需要注意全体序列异或的出现次数需要特判一下,为 1。
整理一下,答案应该为:
$$
\sum_{i=0}^{n-2} \oplus_{k=0}^{i} a_i\times 2\times 3^{n-2-i} + \oplus_{k=0}^{n-1} a_i
$$
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | #include<bits/stdc++.h>#define int long long
 using namespace std;
 
 constexpr int mod = 1e9 + 7;
 
 void solve(){
 int n; cin >> n;
 vector<int> a(n);
 for(int i = 0; i < n; i++) cin >> a[i];
 
 vector<int> p3(n, 1);
 for(int i = 1; i < n; i++) p3[i] = p3[i - 1] * 3 % mod;
 
 int pre = 0;
 
 int res = 0;
 for(int i = 0; i < n - 1; i++){
 pre ^= a[i];
 res += pre * 2 * p3[n - 2 - i];
 res %= mod;
 }
 pre ^= a[n - 1];
 res = (res + pre) % mod;
 
 cout << res << '\n';
 }
 
 signed main(){
 ios::sync_with_stdio(0);
 cin.tie(0);
 solve();
 return 0;
 }
 
 |