本文主要是介绍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−(m−cnt) 的位置长度 l e n len len ,将这段长度全部赋值相同的数,转换 01 , f l a g = f l a g ⊕ 1 01,flag = flag \oplus 1 01,flag=flag⊕1 , 然后减去这段区间产生的子矩形数量 n e e d − m i d ∗ ( m i d + 1 ) 2 need -\frac{mid*(mid+1)}{2} need−2mid∗(mid+1) ,直到 n e e d = 0 need = 0 need=0,这个时候我们就构造出一个符合情况的序列了。
解释二分为什么是找大于等于 n e e d − ( m − c n t ) need - (m - cnt) need−(m−cnt) ,而不是直接找大于等于 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,m≤7 可以第一时间判断爆搜,概率不均衡,所以直接带入概率进去算就完事了,
这题最坑在翻译攻击次数最少的士兵攻击
这句话上。
代码块
#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 0≤r−l≤d ,问你选的区间 [ l , r ] [l,r] [l,r] 后,按照题面那条公式更新数组的值 ,并且求得相邻两个数相减的绝对值最大。
解题思路
观察到范围 n ≤ 5000 n \le 5000 n≤5000 ,直接就想到 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 ai−d ,正反扫一遍取最大值即可。
代码块
#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届沈阳站部分题解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!