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

相关文章

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. 将日期转换为二进制表示 思路分析

项目实战系列三: 家居购项目 第四部分

购物车 🌳购物车🍆显示购物车🍆更改商品数量🍆清空购物车&&删除商品 🌳生成订单 🌳购物车 需求分析 1.会员登陆后, 可以添加家居到购物车 2.完成购物车的设计和实现 3.每添加一个家居,购物车的数量+1, 并显示 程序框架图 1.新建src/com/zzw/furns/entity/CartItem.java, CartItem-家居项模型 /***

码蹄集部分题目(2024OJ赛9.4-9.8;线段树+树状数组)

1🐋🐋配对最小值(王者;树状数组) 时间限制:1秒 占用内存:64M 🐟题目思路 MT3065 配对最小值_哔哩哔哩_bilibili 🐟代码 #include<bits/stdc++.h> using namespace std;const int N=1e5+7;int a[N],b[N],c[N],n,q;struct QUERY{int l,r,id;}que