[每日随题1] 模拟 - 差分数组 - 树状数组
整体概述
- 难度:800 -> 1200 -> 1600
1742B.Increasing
-
标签:模拟
-
前置知识:无
-
难度:Div.4.B 800
题目描述:

输入格式:

输出格式:

样例输入:
3
4
1 1 1 1
5
8 7 1 3 4
1
5
样例输出:
NO
YES
YES
解题思路:
-
要求最后数组严格递增,即不存在相同元素,即可满足题意。
-
那么我们把数组排个序,相邻元素不相同,即不存在相同元素。
完整代码
#include<bits/stdc++.h>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 100+5;
int a[N];
inline string solve(){
int n; cin >> n;
for(int i=1;i<=n;i++) cin >> a[i];
sort(a+1,a+1+n);
for(int i=2;i<=n;i++) if(a[i] == a[i-1]) return "No";
return "Yes";
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T; cin >> T;
while(T--) cout << solve() << '\n';
return 0;
}
892B.Wrath
-
标签:差分数组
-
前置知识:无
-
难度:Div.2.B 1200
题目描述:

输入格式:

输出格式:

样例输入:
4
0 1 0 10
2
0 0
10
1 1 3 0 0 0 2 1 0 3
样例输出:
1
2
3
解题思路:
-
我们注意到所有人同时行动,杀死一个范围内的所有人。
-
那么考虑统计每个人被打到的次数,即 \(n\) 次 区间修改,每次将一个范围上所有人 \(+1\)。最后统一查询,查询有多少个人没有被打到。用差分数组即可。
完整代码
#include<iostream>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 1e6+5;
int d[N];
inline void solve(){
int n; cin >> n;
for(int i=1,x;i<=n;i++){
cin >> x;
d[max(0ll,i-x)] += 1, d[i] -= 1;
}
int res = 0;
for(int i=1;i<=n;i++){
d[i] += d[i-1];
if(!d[i]) ++res;
}
cout << res;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T; T = 1;
while(T--) solve();
return 0;
}
830B.Cards Sorting
-
标签:树状数组
-
前置知识:STL-set
-
难度:Div.1.B 1600
题目描述:

输入格式:

输出格式:

样例输入:
4
6 3 1 2
1
1000
7
3 3 3 3 3 3 3
样例输出:
7
1
7
解题思路:
-
模拟操作的过程发现,最耗时的是 将牌放到牌堆底部,所以我们不能真的每取出一张就一张张移动牌的位置。
-
我们发现整个操作过程牌的相对位置保持不变,那么我们用一个指针 \(p\) 记录下上一张被取走的牌的位置,再记录下每一张牌是否被取走了。那么此时的牌堆顶的位置,就是 \(p\) 下方第一张存活的牌。
之后考虑模拟整个取牌的过程,从小到大依次取每一个数值。我们需要知道在指针 \(p\) 下方第一张数值为 \(x\) 的牌的位置,那么可以考虑记录下所有数值为 \(x\) 的牌的位置,进行二分。
如果 \(p\) 后方没有找到,说明 \(x\) 牌在 \(p\) 的前面,那么我们在从头找到第一张即可。
-
于是我们便得到了下一张会被取走的牌的位置,而这个过程中需要经过的牌的数量,便是从 \(p\) 到牌 \(x\) 中所有存活的牌的张数,我们记存活为 \(1\),被取走为 \(0\),可以用树状数组快速查询一个范围上有多少个 \(1\)。
那么每取走一张牌加上正确的张数,再修改 \(p\) 的位置,模拟一遍即可。
-
复杂度 \(O(n\times log_2^n)\)
完整代码
#include<bits/stdc++.h>
#pragma optimize(2)
#define int long long
using namespace std;
const int N = 1e5+5;
int n, a[N], tr[N];
set<int> idx[N];
inline void add(int x,int v){
for(int i=x;i<=n;i+=i&-i) tr[i]+=v;
}
inline int sum(int l,int r){
int res = 0;
if(l == 0) l = 1;
for(int i=r;i;i&=i-1) res += tr[i];
for(int i=l-1;i;i&=i-1) res -= tr[i];
return res;
}
inline void solve(){
cin >> n;
for(int i=1;i<=n;i++){
cin >> a[i];
idx[a[i]].insert(i);
add(i,1);
}
sort(a+1,a+1+n);
int p = 0,res = 0;
for(int i=1;i<=n;i++){
auto it = idx[a[i]].upper_bound(p);
if(it == idx[a[i]].end()){
res += sum(p,n);
p = 0, it = idx[a[i]].upper_bound(p);
}
res += sum(p,*it);
p = *it;
add(p,-1);
}
cout << res;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T; T = 1;
while(T--) solve();
return 0;
}

每日练题中,难度简单,一起保持手感
浙公网安备 33010602011771号