AtCoder Beginner Contest 250 A - E 題解
阿新 • • 發佈:2022-05-13
閒來無事,突然想 vp 一場之前忙的來不及做的
A - Adjacent Squares
這題沒想到居然還會卡了一下
給出一個圖,給出當前位置,看看有多少個格子相鄰
行和列分別判斷就好
#include <iostream> using namespace std; int main() { int n, m; cin >> n >> m; int x, y; cin >> x >> y; int cnt = 0; if(n == 1) cnt += 2; else if(x == 1 || x == n) cnt++; if(m == 1) cnt += 2; else if(y == 1 || y == m) cnt++; cout << 4 - cnt << endl; return 0; }
B - Enlarged Checker Board
一個模擬,算了一下並不會爆空間,就直接寫好再列印了
#include <iostream> using namespace std; const int maxn = 110; char s[maxn][maxn]; int main() { int n, a, b; cin >> n >> a >> b; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { char now = (i + j) % 2 == 0 ? '.' : '#'; for(int x=i*a; x<i*a+a; x++) { for(int y=j*b; y<j*b+b; y++) { s[x][y] = now; } } } } for(int i=0; i<a*n; i++) { for(int j=0; j<b*n; j++) cout << s[i][j]; cout << endl; } return 0; }
C - Adjacent Swaps
這個用桶來處理一下位置,然後每次詢問的時候桶和陣列同時維護
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int maxn = 2e5 + 10; int num[maxn], alp[maxn]; int main() { int n, m; scanf("%d%d", &n, &m); for(int i=1; i<=n; i++) num[i] = alp[i] = i; while(m--) { int x; scanf("%d", &x); if(alp[x] == n) x = num[n-1]; int way = alp[x]; int a = num[way]; int b = num[way + 1]; swap(num[way], num[way+1]); swap(alp[a], alp[b]); } for(int i=1; i<=n; i++) { if(i != 1) printf(" "); printf("%d", num[i]); } printf("\n"); return 0; }
D - 250-like Number
這個題比較有趣
首先素數的話先用一個尤拉篩預處理一下
接著要尋找合理的情況,本來是想用 \(O(n^2)\) 強行莽一下,但是一直死活寫不對,就突然想到二分,一下就過了
因為 \(k = p * q ^ 3\) 且有 \(p < q\),所以可以列舉 \(q\),然後再找有多少個符合的 \(p\)
而找 \(p\) 的數量,可以直接用二分去尋找第一個大到不符合要求的 \(p\) 的位置,然後知道有多少個 \(p\) 符合條件
這題比較友好的一點是,因為查詢的是素數乘積,所以不會出現說相同一個數字有多種分解的情況,就不用查重,不然還得用一個 set 去維護
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
const int maxn = 1e6 + 10;
int prime[maxn], tp = 0;
long long p[maxn];
void init()
{
int n = 1e6 + 1;
for(int i=2; i<n; i++) prime[i] = 1;
for(int i=2; i<n; i++)
{
if(prime[i])
{
p[tp++] = i;
for(int j=i+i; j<n; j+=i)
prime[j] = 0;
}
}
}
int main()
{
int t = 0;
init();
long long n;
cin >> n;
for(int i=0; i<tp; i++)
{
long long now = p[i] * p[i] * p[i];
long long x = n / now;
t += upper_bound(p, p + i, x) - p;
}
cout << t << endl;
return 0;
}
E - Prefix Equality
這題也很有趣,大概就是問 \(a\) 陣列前 \(x_i\) 個 和 \(b\) 陣列前 \(y_i\) 個,這兩組各自形成的集合是否相等
尺取
我用的是尺取過的,但是看了別人的題解,好像都是用雜湊來預處理 \(a\) 的字首集合 還有 \(b\) 的字首集合,然後直接判斷是否相等
我認為,如果選定了 \(a\) 陣列的前 \(i\) 個,則在 \(b\) 陣列中,一定有一個範圍 \([l, r]\) 使得答案成立
並且對於這個範圍,有 \(l_{i} \leq l_{i+1}\) 和 \(r_{i} \leq r_{i+1}\),因此可以判斷他是單調的,所以直接尺取區間就行,尺取複雜度為 \(O(n)\)
因為要維護一個桶,所以用了 \(map\)
總的時間複雜度為 \(O(nlogn)\)
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const int maxn = 2e5 + 10;
int a[maxn], b[maxn];
pii num[maxn];
int main()
{
int n;
scanf("%d", &n);
map<int, int> r_vis, l_vis;
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
for(int i=1; i<=n; i++) scanf("%d", &b[i]);
b[++n] = a[1];
int l = 1, r = 1, cnt = 0;
for(int i=1; i<=n; i++)
{
if(r_vis[a[i]] == 0) r_vis[a[i]] = 1;
if(l_vis[a[i]] == 0) {cnt++; l_vis[a[i]] = 1;}
while(l <= n && cnt > 0)
{
if(l_vis[b[l]] == 1) cnt--;
l_vis[b[l]] = 2;
l++;
}
while(r <= n && r_vis[b[r]]) r++;
num[i] = make_pair(l - 1, r - 1);
}
int m;
scanf("%d", &m);
for(int i=0; i<m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
if(y >= num[x].first && y <= num[x].second) printf("Yes\n");
else printf("No\n");
}
return 0;
}