ABC238 复盘
[ABC238A] Exponential or Quadratic
思路解析
通过“指数爆炸”的特点可以发现当 \(n \ge 5\) 或 \(n = 1\) 时 \(2^n\) 是大于 \(n^2\) 的,所以一个 if
即可
code
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
if(n >= 5 || n == 1) cout << "Yes";
else cout << "No";
return 0;
}
[ABC238B] Pizza
思路解析
切披萨,如果披萨的第 \(i^\circ\) 上被切开了,我们就将 \(i\) push_back
进一个 vector
中,最后排序统计相邻两个元素之间的距离就是比萨的角度。
注意 \(0^\circ\) 也有一道切口。
code
#include<bits/stdc++.h>
using namespace std;
const int N = 400;
int n, a[N];
int main() {
cin >> n;
int idx = 0;
vector<int> v;
for(int i = 1; i <= n; i++) {
cin >> a[i];
idx = (idx + a[i]) % 360;
v.push_back(idx);
}
v.push_back(0); v.push_back(360);
sort(v.begin(), v.end());
int ans = -1;
for(int i = 0; i < v.size() - 1; i++) {
ans = max(ans, v[i + 1] - v[i]);
}
cout << ans;
return 0;
}
[ABC238C] digitnum
思路解析
找规律发现,\(f(i)=x-10^{\lfloor \log_{10}x \rfloor}+1\),于是就对于每一个 \(\lfloor \log_{10}x \rfloor = i\) 的数,单独统计这些数对答案的贡献即可。
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il __int128
const il mod = 998244353;
ll n;
il sum(il x) {
return ((x + 1) * x / 2) % mod;
}
int main() {
cin >> n;
il s = 1, ans = 0;
while(s <= n) {
ans = (ans + sum(min((il)n, s * (il)10 - 1) - s + 1)) % mod;
s = s * 10;
}
cout << (ll)ans;
return 0;
}
[ABC238D] AND and SUM
思路解析
首先可以很简单地发现 \(x,y\) 都大于等于 \(a\),所以如果 \(2 \times s > a\) 答案就绝对是 No
。其次,还需要判断除了 \(a\) 以外的其它位上的值能否填补上 \(s-a\),若位数不够则输出No
,否则输出 Yes
。
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll t, a, s;
bitset<80> bs;
int main() {
cin >> t;
while(t--) {
bs ^= bs;
cin >> a >> s;
for(int i = 0; i <= 60; i++) {
bs[i] = ((a >> i) & 1);
}
ll b = a + a;
for(int i = 60; i >= 0; i--) {
if(bs[i]) continue;
if(b + (1ll << i) <= s) b += (1ll << i);
}
if(b == s) cout << "Yes\n";
else cout << "No\n";
}
return 0;
}
[ABC238E] Range Sums
思路解析
首先我们发现如果我们知道了区间 \([1,l-1]\) 和区间 \([l,r]\),我们就能知道 \([1,r]\)。同理如果我们知道 \([1,x]\) 和 \([1,y]\),我们就能知道 \([x,y]\)。这就意味着如果我们知道了区间 \([l,r]\),也就是相当于连通了 \([1,l-1]\) 和 \([1,r]\),这时如果我们也知道 \([1,r-1]\),我们就能知道 \([1,r]\),于是便可以很轻松将这道题转换成一个类似连通块的问题,目标就是求 \([1,0]\) 和 \([1,n]\) 是否连通,于是用并查集维护是否连通即可。
code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, q, fa[N];
int find(int x) {
if(fa[x] == x) return x;
else return (fa[x] = find(fa[x]));
}
int main() {
cin >> n >> q;
for(int i = 1; i <= n; i++) fa[i] = i;
while(q--) {
int l, r;
cin >> l >> r;
fa[find(l - 1)] = find(r); //代表连通两个区间
}
if(find(0) == find(n)) cout << "Yes";
else cout << "No";
return 0;
}
[ABC238F] Two Exams
思路解析
这题很麻烦,因为有两个维度。所以可以想到先按照第一维排序,这样就不需要考虑第二维的问题。其次再发现数据范围小,可以想到能用 dp 做,接下来就考虑如何 dp。首先我们要知道我们遍历到了第几个公民,同时还要知道还剩下几个代表名额,同时我们还需要思考第二维对选择代表的影响。于是想到 \(f_{i,j,k}\) 表示考虑完了前 \(i\) 个人,选了 \(j\) 个公民做代表,在没有被选为代表的人中第二维的值最小的值是 \(k\)。原因是我们已经按照第一位排好了序,当前的人在第一维上的排名一定落后于第二维是 \(k\) 的人,如果当前人在第二维上依然落后于 \(k\),就必定不可以选。
然后考虑状态转移,分为选和不选两种情况。
-
如果不选,\(j\) 不变,但需要更新 \(k\),所以可得 \(f_{i,j,\min(k,q_{i})} \gets f_{i-1,j,k}\)
-
如果选,则 \(j\) 需要加一,同时比较 \(q_{i}\) 和 \(k\),可得 \(f_{i,j,k} \gets f_{i-1,j-1,k}\)
最后的答案就是 \(\sum_{i=1}^{n+1}f_{n,m,i}\)。
细节:初始时没有一个人不选,\(k\) 为 \(n+1\),以及统计答案时也有可能没有一个人不选,记得遍历到 \(n+1\)。
code
#include<bits/stdc++.h>
using namespace std;
#define PII pair<int, int>
#define fir first
#define sec second
const int N = 310, mod = 998244353;
int n, m, f[N][N][N];
PII a[N];
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> a[i].fir;
}
for(int i = 1; i <= n; i++) {
cin >> a[i].sec;
}
sort(a + 1, a + n + 1, [](PII x, PII y) { return x.fir < y.fir;});
f[0][0][n + 1] = 1;
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= m; j++) {
for(int k = 1; k <= n + 1; k++) {
f[i][j][min(a[i].sec, k)] = (f[i][j][min(a[i].sec, k)] + f[i - 1][j][k]) % mod;
if(j > 0 && a[i].sec < k) {
f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k]) % mod;
}
}
}
}
int ans = 0;
for(int i = 1; i <= n + 1; i++) ans = (ans + f[n][m][i]) % mod;
cout << ans;
return 0;
}
标签:code,int,cin,find,ABC238,using,include,复盘
From: https://www.cnblogs.com/2020luke/p/18045775