2022 第47届沈阳站部分题解

2023-10-14 00:40
文章标签 部分 2022 题解 47 沈阳站

本文主要是介绍2022 第47届沈阳站部分题解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

F. Half Mixed

题面:
在这里插入图片描述

题目链接:F. Half Mixed

简要题意:
  给出 n , m n,m n,m, 求构造 n n n m m m 列 只包含 0 , 1 {0,1} 0,1 的数列,要求全部纯净块的数量 = 全部混合块的数量。纯净块指子矩形内所有数字要么全部是 0 0 0 ,要么全部是 1 1 1,而混合块则相反:子矩形内要包括 0 , 1 {0,1} 0,1两种数字,问是否能构造出,若是能打印你所构造的序列。

解法思路:根据官方题解与自己理解结合而成

n 行的子矩形数量为 n ∗ ( n + 1 ) 2 \frac{n*(n+1)}{2} 2n(n+1)
m行的子矩形数量为 m ∗ ( m + 1 ) 2 \frac{m*(m+1)}{2} 2m(m+1)

如果 n ∗ ( n + 1 ) 2 ∗ m ∗ ( m + 1 ) 2 \frac{n*(n+1)}{2} * \frac{m*(m+1)}{2} 2n(n+1)2m(m+1)是奇数,那么永远构造不出来,始终会多出一个数,这个时候输入No即可.

若相乘是偶数,代表有解,假设 m ∗ ( m + 1 ) 2 \frac{m*(m+1)}{2} 2m(m+1) 是偶数,考虑 1 × m 1 \times m 1×m 的情况, 1 × m 1 \times m 1×m 的子矩形有 m ∗ ( m + 1 ) 2 \frac{m*(m+1)}{2} 2m(m+1) ,设长度 ( ∑ i = 1 k l 1 , l 2 , ⋯ , l k ) = m (\sum_{i=1}^{k}l_1,l_2, \cdots,l_k) = m (i=1kl1,l2,,lk)=m,每一个 l i l_i li 长度的子矩形数量为 l i ∗ ( l i + 1 ) 2 \frac{l_i*(l_i+1)}{2} 2li(li+1) ,纯净子矩形数量即为 ∑ i = 1 k l i ∗ ( l i + 1 ) 2 \sum_{i=1}^{k}\frac{l_i*(l_i+1)}{2} i=1k2li(li+1),要满足纯净子矩形 = = = 混合子矩形,则 ∑ i = 1 k l i ∗ ( l i + 1 ) 2 = m ∗ ( m + 1 ) 4 \sum_{i=1}^{k}\frac{l_i*(l_i+1)}{2} = \frac{m*(m+1)}{4} i=1k2li(li+1)=4m(m+1) 且要满足 ∑ i = 1 k l i = m \sum_{i=1}^{k} l_i = m i=1kli=m,其中 m ∗ ( m + 1 ) 2 \frac{m*(m+1)}{2} 2m(m+1) 代表 m m m 列子矩形总数,要纯净和混合数量相同只需要两边各占一半,即纯子矩形数量满足 = m ∗ ( m + 1 ) 4 \frac{m*(m+1)}{4} 4m(m+1)

每次选择尽可能大的 l i l_i li 的长度,二分 m i d mid mid 长度,找到最大满足 m i d ∗ ( m i d + 1 ) 2 \frac{mid*(mid+1)}{2} 2mid(mid+1) 大于等于 n e e d − ( m − c n t ) need - (m - cnt) need(mcnt) 的位置长度 l e n len len ,将这段长度全部赋值相同的数,转换 01 , f l a g = f l a g ⊕ 1 01,flag = flag \oplus 1 01,flag=flag1 , 然后减去这段区间产生的子矩形数量 n e e d − m i d ∗ ( m i d + 1 ) 2 need -\frac{mid*(mid+1)}{2} need2mid(mid+1) ,直到 n e e d = 0 need = 0 need=0,这个时候我们就构造出一个符合情况的序列了。

解释二分为什么是找大于等于 n e e d − ( m − c n t ) need - (m - cnt) need(mcnt) ,而不是直接找大于等于 n e e d need need
因为 m - cnt 代表剩下的位置需要 01 交替摆放,如果直接找大于等于 need,可能存在这个位置 mid 填了之后纯子矩形数量够了,但是没有满足构造出来长度和 = m 的情况

只要满足 1 × m 1 \times m 1×m的情况,然后铺满 n n n行也是满足要求的

代码块

#include<bits/stdc++.h>
using namespace std;#define ll long long
#define sc(x) scanf("%d",&x)
#define _sc(x) scanf("%lld",&x)
#define pf(x) printf("%d",x);
#define _pf(x) printf("%lld",x);
#define FOR(i,a,b) for(int i = a;i<=b;++i)
#define _FOR(i,a,b) for(int i = a;i<b;++i)
#define pb push_back
#define lb lowber_bound
#define ub upper_bound
#define lson(x) ((x) * 2)
#define rson(x) ((x) * 2 + 1)const ll mod = 1e9+7;
const ll maxn = 1e6+10;
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;ll pow2(ll a,ll n){ ll res = 1ll;while(n){if(n&1) res = (res*a)%mod;a = (a*a)%mod;n >>= 1;}return res;}ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; }int T;
ll n,m;
int a[maxn];
ll in[maxn];
void init(){in[1] = 1;for(int i = 2;i <= 1000000;++i){in[i] = in[i - 1] + i;} 
}
void calc(ll x){ll need = (x + 1) * x / 4;int cnt = 1 , flag = 1;while(need){/* 二分寻找最大的长度need - x + cnt ===> 所需要的 need 数量 - 还剩下(x - cnt)填补交替01形成的纯子矩形 */int pos = lower_bound(in + 1, in + 1 + 1000000 , need - (x - cnt)) - (in);for(int i = 1;i<=pos;++i){a[cnt++] = flag;}need -= in[pos];flag ^= 1;}
}void solve(){cin >> n >> m;ll sumN = (n + 1) * n / 2  , sumM = (m + 1) * m / 2;if((sumN & 1) && (sumM & 1)){cout << "No\n";return ;}cout << "Yes\n";int flag = 0;if(sumM & 1){swap(n,m);flag = 1;}calc(m);if(flag){for(int i = 1;i <= m;++i){for(int j = 1;j<=n;++j){cout << a[i] << " \n"[j == n];}}}else{for(int i = 1;i <= n;++i){for(int j = 1;j<= m;++j){cout << a[j] << " \n"[j == m];}}		}}
int main(void){std::ios::sync_with_stdio(0);std::cin.tie(0);init();cin >> T;while(T--){solve();}return 0;
} 

L. Tavern Chess

题面
在这里插入图片描述

题目描述

给定 n n n m m m 分别代表Alice的团队士兵数量和鲍勃的团队士兵数量,现在两队的士兵进行攻击,若爱丽丝的士兵数量 n > m n > m n>m ,则爱丽丝先手攻击鲍勃,如果是 m > n m > n m>n 则鲍勃先手先攻击爱丽丝,如果 n = m n = m n=m 则两边各 50 % 50\% 50%的机会攻击对方。问最后爱丽丝赢得概率,鲍勃赢得概率,打平的概率。

攻击的规则如下:双方回合战,即每一轮攻击后交换攻击权,每次攻击由攻击次数最少且血量大于0的最左侧士兵攻击。士兵血量小于等于0视为死亡。

翻译巨坑:攻击次数最少的最左边士兵攻击

解法思路
观看范围 n , m ≤ 7 n,m \le 7 n,m7 可以第一时间判断爆搜,概率不均衡,所以直接带入概率进去算就完事了,
这题最坑在翻译攻击次数最少的士兵攻击这句话上。

代码块

#include<bits/stdc++.h>
using namespace std;#define ll long long
#define sc(x) scanf("%d",&x)
#define _sc(x) scanf("%lld",&x)
#define pf(x) printf("%d",x);
#define _pf(x) printf("%lld",x);
#define FOR(i,a,b) for(int i = a;i<=b;++i)
#define _FOR(i,a,b) for(int i = a;i<b;++i)
#define pb push_back
#define lb lowber_bound
#define ub upper_bound
#define lson(x) ((x) * 2)
#define rson(x) ((x) * 2 + 1)const ll mod = 1e9+7;
const ll maxn = 1e6+10;
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;ll pow2(ll a,ll n){ ll res = 1ll;while(n){if(n&1) res = (res*a)%mod;a = (a*a)%mod;n >>= 1;}return res;}ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; }int T;
ll n,m;ll a[8],b[8];
ll Aatk[8] , Batk[8];
ll AtkCnt[8] , BtkCnt[8];
double WinA , WinB , draw;int check(){int f1 = 1, f2 = 1;for (int i = 0; i < n; ++i){if (a[i] > 0){f1 = 0;break;}}for (int i = 0; i < m; ++i){if (b[i] > 0){f2 = 0;break;}}if(f1 && f2) return 2; // 打平局面if(f2) return 0;	//  A Winif(f1) return 1; // B Winreturn 3; // 还未完成的局面
}int Calc(int n , ll arr[8]){int res = 0;for (int i = 0; i < n; ++i){if(arr[i] <= 0) continue;++res;}return res;
}void dfs(auto a,auto b,int opt , double prob){int t = check();if(t != 3){if(t == 2) draw += prob;if(t == 0) WinA += prob;if(t == 1) WinB += prob;return ;}int size = Calc((opt == 0 ? m : n) , (opt == 0 ? b : a));double prob2 = prob / (1.0 * size);if(opt == 0){int pos , miCnt = 1e9+5;for (int i = 0; i < n; ++i){if(a[i] <= 0) continue;if(AtkCnt[i] < miCnt){miCnt = AtkCnt[i];pos = i;}}for(int i = 0;i<m;++i){if(b[i] <= 0) continue;b[i] -= Aatk[pos];a[pos] -= Batk[i];AtkCnt[pos]++;dfs(a,b,opt ^ 1,prob2);b[i] += Aatk[pos];a[pos] += Batk[i];AtkCnt[pos]--;			}}else{int pos , miCnt = 1e9+5;for (int i = 0; i < m; ++i){if(b[i] <= 0) continue;if(BtkCnt[i] < miCnt){miCnt = BtkCnt[i];pos = i;}}for(int i = 0;i<n;++i){if(a[i] <= 0) continue;a[i] -= Batk[pos];b[pos] -= Aatk[i];BtkCnt[pos]++;dfs(a,b,opt ^ 1,prob2);a[i] += Batk[pos];b[pos] += Aatk[i];BtkCnt[pos]--;		}}
}void solve(){cin >> n >>  m;for (int i = 0; i < n; ++i){cin >> a[i]; Aatk[i] = a[i];}for (int i = 0; i < m; ++i){cin >> b[i]; Batk[i] = b[i];}if(n > m){dfs(a,b,0,1);}else if(m > n){dfs(a,b,1,1);}else{dfs(a,b,0,0.5);dfs(a,b,1,0.5);}cout << fixed << setprecision(15) << WinA << "\n" << WinB << "\n" << draw << "\n";}
int main(void){std::ios::sync_with_stdio(false);std::cin.tie(0);T = 1;while(T--){solve();}return 0;
} 

C. Clamped Sequence

题面
在这里插入图片描述

题目描述

给定 n n n d d d ,代表有 n n n 个数,你可以选取一个区间 [ l , r ] [l,r] [l,r] 要满足 0 ≤ r − l ≤ d 0 \le r - l \le d 0rld ,问你选的区间 [ l , r ] [l,r] [l,r] 后,按照题面那条公式更新数组的值 ,并且求得相邻两个数相减的绝对值最大。

解题思路
观察到范围 n ≤ 5000 n \le 5000 n5000 ,直接就想到 n 2 n^2 n2 时间复杂度的解法。我们可以以每个数 a i a_i ai 作为左端点 ,右端点即 a i + d a_i +d ai+d ,然后 O ( n ) O(n) O(n) 修改数组的值,加上两两差的绝对和取个最大值,最后还原数组。然后再以右端点 a i a_i ai,左端点 a i − d a_i - d aid ,正反扫一遍取最大值即可。

代码块

#include<bits/stdc++.h>
using namespace std;#define ll long long
#define sc(x) scanf("%d",&x)
#define _sc(x) scanf("%lld",&x)
#define pf(x) printf("%d",x);
#define _pf(x) printf("%lld",x);
#define FOR(i,a,b) for(int i = a;i<=b;++i)
#define _FOR(i,a,b) for(int i = a;i<b;++i)
#define pb push_back
#define lb lowber_bound
#define ub upper_bound
#define lson(x) ((x) * 2)
#define rson(x) ((x) * 2 + 1)const ll mod = 1e9+7;
const ll maxn = 1e6+10;
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;ll pow2(ll a,ll n){ ll res = 1ll;while(n){if(n&1) res = (res*a)%mod;a = (a*a)%mod;n >>= 1;}return res;}ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; }int T;
ll n,m;ll a[5005] , b[5005];void solve(){ll d;cin >> n >> d;for (int i = 0; i < n; ++i){cin >> a[i]; b[i] = a[i];}ll ans = 0;for(int i = 0 ; i < n ;++i){int le = a[i] , ri = a[i] + d;for(int j = 0 ; j < n ; ++j){if(b[j] < le) b[j] = le;else if(b[j] > ri) b[j] = ri;}ll res = 0;for(int j = 0 ; j + 1< n ; ++j){res += abs(b[j] - b[j + 1]);b[j] = a[j];}b[n - 1] = a[n - 1];ans = max(res, ans);}for(int i = n - 1 ; i >= 0 ;--i){int le = a[i] - d , ri = a[i];for(int j = 0 ; j < n ; ++j){if(b[j] < le) b[j] = le;else if(b[j] > ri) b[j] = ri;}ll res = 0;for(int j = 0 ; j + 1< n ; ++j){res += abs(b[j] - b[j + 1]);b[j] = a[j];}b[n - 1] = a[n - 1];ans = max(res, ans);}	cout << ans << "\n";
}
int main(void){std::ios::sync_with_stdio(false);std::cin.tie(0);T = 1;while(T--){solve();}return 0;
} 

D. DRX vs. T1

题面
在这里插入图片描述

题目描述

福利签到题:就给出一行字符串,T出现次数多就输出T1,D出现次数多输出DRX

代码块

#include<bits/stdc++.h>
using namespace std;#define ll long long
#define sc(x) scanf("%d",&x)
#define _sc(x) scanf("%lld",&x)
#define pf(x) printf("%d",x);
#define _pf(x) printf("%lld",x);
#define FOR(i,a,b) for(int i = a;i<=b;++i)
#define _FOR(i,a,b) for(int i = a;i<b;++i)
#define pb push_back
#define lb lowber_bound
#define ub upper_bound
#define lson(x) ((x) * 2)
#define rson(x) ((x) * 2 + 1)const ll mod = 1e9+7;
const ll maxn = 1e6+10;
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;ll pow2(ll a,ll n){ ll res = 1ll;while(n){if(n&1) res = (res*a)%mod;a = (a*a)%mod;n >>= 1;}return res;}ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; }int T;
ll n,m;void solve(){string str;map<char,int> mp;cin >> str;for(auto x:str){mp[x]++;}if(mp['T'] > mp['D']) cout << "T1";else cout << "DRX";
}
int main(void){std::ios::sync_with_stdio(false);std::cin.tie(0);T = 1;while(T--){solve();}return 0;
} 

A想补,但是还没理解到位,先写这么多,下次再来

这篇关于2022 第47届沈阳站部分题解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/206957

相关文章

一文详解如何在Python中从字符串中提取部分内容

《一文详解如何在Python中从字符串中提取部分内容》:本文主要介绍如何在Python中从字符串中提取部分内容的相关资料,包括使用正则表达式、Pyparsing库、AST(抽象语法树)、字符串操作... 目录前言解决方案方法一:使用正则表达式方法二:使用 Pyparsing方法三:使用 AST方法四:使用字

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

C - Word Ladder题解

C - Word Ladder 题解 解题思路: 先输入两个字符串S 和t 然后在S和T中寻找有多少个字符不同的个数(也就是需要变换多少次) 开始替换时: tips: 字符串下标以0开始 我们定义两个变量a和b,用于记录当前遍历到的字符 首先是判断:如果这时a已经==b了,那么就跳过,不用管; 如果a大于b的话:那么我们就让s中的第i项替换成b,接着就直接输出S就行了。 这样

笔记整理—内核!启动!—kernel部分(2)从汇编阶段到start_kernel

kernel起始与ENTRY(stext),和uboot一样,都是从汇编阶段开始的,因为对于kernel而言,还没进行栈的维护,所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。         内核起始部分代码被解压代码调用,前面关于uboot的文章中有提到过(eg:zImage)。uboot启动是无条件的,只要代码的位置对,上电就工作,kern

【秋招笔试】9.07米哈游秋招改编题-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收集 100+ 套笔试题,笔试真题 会在第一时间跟新 🍄 题面描述等均已改编,如果和你笔试题看到的题面描述

LeetCode 第414场周赛个人题解

目录 Q1. 将日期转换为二进制表示 原题链接 思路分析 AC代码 Q2. 范围内整数的最大得分 原题链接 思路分析 AC代码 Q3. 到达数组末尾的最大得分 原题链接 思路分析 AC代码 Q4. 吃掉所有兵需要的最多移动次数 原题链接 思路分析 AC代码 Q1. 将日期转换为二进制表示 原题链接 Q1. 将日期转换为二进制表示 思路分析