https://atcoder.jp/contests/abc260/tasks
E - At Least One
题意
给定
N
N
N 个数对
(
A
1
,
B
1
)
,
(
A
2
,
B
2
)
,
…
,
(
A
N
,
B
N
)
\left(A_{1}, B_{1}\right),\left(A_{2}, B_{2}\right), \ldots,\left(A_{N}, B_{N}\right)
(A1,B1),(A2,B2),…,(AN,BN)
对于所有的
i
i
i,都满足
1
≤
A
i
<
B
i
≤
M
1 \leq A_{i}<B_{i} \leq M
1≤Ai<Bi≤M。
如果在一段连续的区间
[
l
,
r
]
[l, r]
[l,r] 中,
N
N
N 个数对的
A
i
A_i
Ai 和
B
i
B_i
Bi 都至少出现了一个,那么说明这个连续区间是 好区间
。
问,长度为
1
,
2
,
.
.
.
,
M
1,2,...,M
1,2,...,M 的 好区间
分别有多少个?
- 1 ≤ N ≤ 2 × 1 0 5 1 \leq N \leq 2 \times 10^{5} 1≤N≤2×105
- 2 ≤ M ≤ 2 × 1 0 5 2 \leq M \leq 2 \times 10^{5} 2≤M≤2×105
- 1 ≤ A i < B i ≤ M 1 \leq A_{i}<B_{i} \leq M 1≤Ai<Bi≤M
思路
将编号 i 都分别挂在 Ai 和 Bi 下面,也就是对于一个数,其对应了多个编号,一共 M 个数。
如果连续的一段数,满足 n 个编号都出现过,那么这段数就是好的。
如果一个好区间确定了是从 l 到 r,那么其往外延伸的区间也是好的。
从前往后遍历每个位置 i
,可以每次用滑动窗口维护最小的满足的区间 [l, r]
,那么这个区间长度就是最短区间,而这个区间向左右延伸的所有区间都是满足的。
为了防止区间重复,这个区间只往左延伸,一直延伸到第一个位置都是满足的。
也就是说,长度 r-l+1
到长度 i
的区间长度都是满足的,这些长度的答案数都 +1(差分实现)。
一共遍历了 M 个位置,每个编号最多出入队两次,总的复杂度为 O ( N + M ) O(N+M) O(N+M)。
Code
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N], ans[N];
int q[N], mp[N];
vector<int> v[N];
bool check(int i)
{
for(int x : v[i])
{
if(mp[x] == 1) return 0;
}
return 1;
}
signed main(){
Ios;
cin >> n >> m;
for(int i=1;i<=n;i++){
int x, y; cin >> x >> y;
v[x].push_back(i);
v[y].push_back(i);
}
int sum = 0;
int hh = 0, tt = -1;
for(int i=1;i<=m;i++)
{
q[++tt] = i;
for(int x : v[i]){
mp[x]++;
if(mp[x] == 1) sum++;
}
while(hh <= tt && check(q[hh])){
for(int x : v[q[hh]]) mp[x]--;
hh++;
}
if(sum == n) ans[tt-hh+1]++, ans[i+1]--;
}
for(int i=1;i<=m;i++) ans[i] += ans[i-1], cout << ans[i] << " ";
return 0;
}
D - Draw Your Cards
题意
有 N 张反着的牌,每张牌上有值
X
i
X_i
Xi,互不相同。
每次从最上面取一张,假设为 X,放到已经取出的牌堆中。
- 找到所有堆最上面的牌中第一个大于等于 X 的牌,放在其上面。
- 如果找不到就另起一堆。
- 如果一个牌堆的牌数等于 K 了,那么这堆牌将会被清除。
问,每个牌是在第几次取牌操作后被清除的?如果没被清除,输出 -1。
1 ≤ K ≤ N ≤ 2 × 1 0 5 1 \leq K \leq N \leq 2 \times 10^{5} 1≤K≤N≤2×105
思路
照着题意模拟就行了,可以编号已有的牌堆,然后记录每张取出的牌所在牌堆号。
把牌推最上面的牌放在 set 里,方便二分找到对应的牌堆。
注意 K = 1 的情况。
Code
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];
vector<int> v[N];
int pos[N], ans[N];
signed main(){
Ios;
cin >> n >> m;
set<int> st;
int cnt = 0;
for(int i=1;i<=n;i++)
{
int x; cin >> x;
auto it = st.lower_bound(x);
if(it != st.end())
{
int tx = *it;
pos[x] = pos[tx];
st.erase(tx);
v[pos[tx]].push_back(x);
if(v[pos[tx]].size() == m)
{
for(int t : v[pos[tx]])
ans[t] = i;
}
else st.insert(x);
}
else{
pos[x] = ++cnt;
v[cnt].push_back(x);
if(m == 1) ans[x] = i;
else st.insert(x);
}
}
for(int i=1;i<=n;i++)
if(ans[i]) cout << ans[i] << "\n";
else cout << "-1\n";
return 0;
}
C - Changing Jewels
题意
给定 X, Y 和一个等级为 n 红宝石。
问,经过下面的转化,最多可以得到多少等级为 1 的蓝宝石?
- 红 n → 红 ( n − 1 ) + X ∗ 蓝 n 红n → 红(n-1) + X * 蓝n 红n→红(n−1)+X∗蓝n;
- 蓝 n → 红 ( n − 1 ) + Y ∗ 蓝 ( n − 1 ) 蓝n → 红(n-1) + Y * 蓝(n-1) 蓝n→红(n−1)+Y∗蓝(n−1);
1 ≤ n ≤ 10 1 \leq n \leq 10 1≤n≤10, 1 < X < 5 1<X<5 1<X<5, 1 ≤ Y ≤ 5 1 \leq Y \leq 5 1≤Y≤5
思路
直接两个递归相互搞 RE 了。。
那就把所有的 蓝n 都先转化出来,都变成 红 和 最后的一个数,然后递归 红 就行了。
由第二个转化可得:
蓝
n
→
红
(
n
−
1
)
+
Y
∗
红
(
n
−
2
)
+
Y
2
∗
红
(
n
−
3
)
+
.
.
.
+
Y
n
−
1
蓝n → 红(n-1) + Y*红(n-2) + Y^2*红(n-3) + ... + Y^{n-1}
蓝n→红(n−1)+Y∗红(n−2)+Y2∗红(n−3)+...+Yn−1
那么
红
n
→
红
(
n
−
1
)
+
X
∗
[
红
(
n
−
1
)
+
Y
∗
红
(
n
−
2
)
+
Y
2
∗
红
(
n
−
3
)
+
.
.
.
+
Y
n
−
1
]
红n → 红(n-1) + X *[红(n-1) + Y*红(n-2) + Y^2*红(n-3) + ... + Y^{n-1}]
红n→红(n−1)+X∗[红(n−1)+Y∗红(n−2)+Y2∗红(n−3)+...+Yn−1]。
Code
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];
int x,y;
int red(int n)
{
if(n < 2) return 0;
int sum = 0;
sum += red(n-1);
int cnt = 0;
for(int i = n-1; i>=0;i--)
{
sum += x*(pow(y, cnt++) * red(i));
}
sum += x * pow(y, n-1);
return sum;
}
signed main(){
Ios;
cin >> n >> x >> y;
cout << red(n);
return 0;
}