Atcoder-ABC150-DEF题解

Atcoder题解汇总

ABC 150

train#1

D. Semi Common Multiple (LCM, 数学推导)

题意

给一个长度为 n(1n105) 数组且 ai 是偶数, 求 [1,M] 有多少个 X 满足对任意 X=ai(p+0.5)

数据范围
1M109

思路

  • X 肯定是 ai 的公倍数, 转换一下式子
  • X=ai2(2p+1), 即 X 一定是 ai2 的奇数倍, 那么只需要 check 一下就好了, 当然 XM

Solution

#include<bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> PII; typedef std::pair<ll, ll> PLL; typedef double db; #define arr(x) (x).begin(),(x).end() #define x first #define y second #define pb push_back #define mkp make_pair #define endl "\n" using namespace std; const ll INF = 2e18; ll gcd(ll a, ll b){ return b ? gcd(b, a % b) : a; } int main(){ ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); ll n, m; cin >> n >> m; vector<ll> a(n); ll LCM = 1; bool fl = false; for(int i = 0;i < n; i++){ cin >> a[i]; a[i] /= 2; if(LCM == INF) continue; LCM = LCM / gcd(a[i], LCM) * a[i]; if(LCM > m) LCM = INF; } if(LCM == INF){ cout << 0 << endl; return 0; } for(int i = 0; i < n; i++){ if((LCM / a[i]) % 2 == 0) fl = true; } if(LCM == INF || fl) cout << 0 << endl; else cout << 1ll * (m / LCM + 1) / 2 << endl; return 0; }

E. Change a Little Bit (组合计数推导)

题意

给定长度为 n 的两个01串 S,T, 定义 f(S,T) 为以下操作最小花费总和:

改变 S[i] , 此次花费定义为操作之前 ST 不同下标数 DCi

数据范围
1N2105
1Ci109

思路

  • 考虑按贡献来计算, 按照每一个 Ci 的贡献来计算, 显然贪心地想, 大的 Ci 要后选, 小的先选
  • 那么假设 Ci 已从大到小排序, 1in, 当 i 不同时, 那么设不包括 i 下标有 j 个数不同, 则 ji , 否则贪心不成立
  • 那么枚举一下 j 的大小, j=0 时, 前面全是相同的数, 其余的数(除开 i) 总共有 ni 个随便什么情况(因为按贡献考虑互相独立), 所以此次贡献为 2niC[i]
  • 更一般的来看, 对于每个 j, 贡献为 2niCij(j+1)C[i], 则对于每个 C[i] 其贡献为 2niC[i]Σj=0i1Ci1j(j+1)
  • 再转化一下, 利用公式 Cnii=n2n1, =2niC[i]((i1)2i2+2i1 , 代码中 i 从 0 开始.
  • 最后一定不要漏掉, 关于每个位置的相同与不同定义是可以变化的 01,10, 00,11 分别属于不同与相同位与位之间可以任意组合 , 所以最后答案还要乘上 2n

Solution

#include<bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> PII; typedef std::pair<ll, ll> PLL; typedef double db; #define arr(x) (x).begin(),(x).end() #define x first #define y second #define pb push_back #define mkp make_pair #define endl "\n" using namespace std; const int mod = 1e9 + 7; const int N = 2e5 + 10; ll mi[N]; // n * 2 ^n-1 int main(){ ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; vector<ll> c(n); mi[0] = 1; for(int i = 1; i <= n; i++) mi[i] = mi[i - 1] * 2ll % mod; for(int i = 0; i < n; i++) cin >> c[i]; sort(arr(c)); reverse(arr(c)); ll ans = 0; for(int i = 0; i < n; i++){ int x = i + 1; ans = (ans + mi[n - x] % mod * c[i] % mod * (i * mi[max(i - 1, 0)] % mod + mi[i])) % mod; } cout << mi[n] * ans % mod << endl; return 0; }

F. Xor Shift (XOR差分性 + KMP)

题意

给了长度为 n 的两个序列 a,b, 找出所有的 (k,x) 满足 bi=ai+kmodNXORx

数据范围
1n2105
0ai230

思路

  • b[i]=a[i+k]^X -> b[i]^a[i+k] = X = b[i+1]^a[i+k+1] -> b[i] ^ b[i + 1] = a[i+k] ^ a[i+k+1]
  • 转化后对 a,b 作差分, 答案转化为 ba 中的出现次数, 就是有多少个 k, 对于每个 kx 很好求
  • 显然将 b 作为模板串需要将 a 拉成环再破成链
  • 最后做一次 KMP 就可以求解

Solution

#include<bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> PII; typedef std::pair<ll, ll> PLL; typedef double db; #define arr(x) (x).begin(),(x).end() #define x first #define y second #define pb push_back #define mkp make_pair #define endl "\n" using namespace std; const int N = 2e5 + 10; int ne[2 * N], n, ans = 0; void get_ne(vector<int>& s){ int len = 2 * n; ne[1] = 0; for(int i = 2, j = 0; i <= len; i++){ while(j && s[j + 1] != s[i]) j = ne[j]; if(s[i] == s[j + 1]) j++; ne[i] = j; } } vector<int> Match(vector<int>& s, vector<int>& p){ int lens = 2 * n - 1, lenp = n; vector<int> res; for(int i = 1, j = 0; i <= lens; i++){ while(j && s[i] != p[j + 1]) j = ne[j]; if(s[i] == p[j + 1]) j++; if(j == lenp){ res.pb(i - n); ans++; j = ne[j]; } } return res; } int main(){ ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n; vector<int> a(2 * n + 1, 0), xa(n + 1, 0); vector<int> b(n + 1, 0), xb(n + 1, 0); for(int i = 1; i <= n; i++) cin >> xa[i]; for(int i = 1; i <= n; i++) cin >> xb[i]; for(int i = 1; i <= n; i++){ if(i != n){ a[i] = xa[i] ^xa[i + 1]; b[i] = xb[i] ^ xb[i + 1]; } else{ a[i] = xa[i] ^ xa[1]; b[i] = xb[i] ^ xb[1]; } a[i + n] = a[i]; } get_ne(a); auto res = Match(a, b); for(auto k: res){ cout << k << " " << (xb[1] ^ xa[1 + k]) << endl; } return 0; }

__EOF__

本文作者Roshin
本文链接https://www.cnblogs.com/Roshin/p/ABC151.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Roshin  阅读(113)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· Apache Tomcat RCE漏洞复现(CVE-2025-24813)
-->
点击右上角即可分享
微信分享提示