vector
Simons and Posting Blogs
题目大意
发布一篇博客时,会按顺序处理博客里提到的用户:
- 如果这个用户已经在 当前队列 QQ 里,就把它移动到 QQ 的最前面(“提到”一次,相当于“激活”一下它)。
- 如果这个用户不在 QQ 里,就把它插入到 QQ 的最前面。
我们要选择 博客发布的顺序,使得最终 QQ 的字典序最小。
代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void so(){
int n;cin>>n;
vector<vector<int>>a(n,vector<int>{});
for(int i=0;i<n;i++){
int l;cin>>l;
set<int>st;
for(int j=0;j<l;j++){
int x;cin>>x;a[i].push_back(x);
}reverse(a[i].begin(),a[i].end());
vector<int>rep;
for(int j=0;j<l;j++){
if(st.empty()||st.find(a[i][j])==st.end()){
rep.push_back(a[i][j]);
st.insert(a[i][j]);
}
}a[i]=rep;
}sort(a.begin(),a.end());
vector<int>ans;
map<int,int>seen;
while(true){
if(a.empty())break;
for(int i:a[0]){
if(seen[i]==0){
seen[i]=1;
ans.push_back(i);
}
}vector<vector<int>>repp;
for(int i=1;i<a.size();i++){
vector<int>rep;
for(int j=0;j<a[i].size();j++){
if(!seen[a[i][j]])rep.push_back(a[i][j]);
}repp.push_back(rep);
}a=repp;
sort(a.begin(),a.end());
}
for(int i:ans){cout<<i<<' ';}
cout<<'\n';
}int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--){so();}
}
思路
1.总体思路:把b[i]逆序后排序,字典序小的优先出现,然后去掉已经出现过的,重复这一过程(由数据大小知)
stl
1. set
set<int> st;
st.empty()
st.find(a[i][j]) == st.end()
st.insert(a[i][j])
- 有序集合,元素不重复,自动排序(默认升序)。
st.empty():判断集合是否为空。st.find(x):查找x,返回迭代器,如果没找到返回st.end()。st.insert(x):插入元素,如果已存在则插入失败(但这里没检查返回值)。
在这里用于 去除同一篇博客内重复的用户(只保留第一次出现的)。
2. map
map<int,int> seen;
seen[i] == 0
seen[i] = 1
- 键值对映射,自动按键排序。
map<int,int>的键是用户 ID,值是标记(0 未出现,1 已出现)。seen[i]:如果键i不存在,会默认初始化为 0(因为int的默认构造是 0)。- 用来标记一个用户是否已经被加入最终答案。
3. sort
sort(a.begin(), a.end());
- 排序算法,默认升序。
- 对
vector<vector<int>>排序时,按字典序比较两个vector<int>。 - 这里用于每次循环后重新排序剩余博客,保证每次取第一个博客(即当前字典序最小的博客)来处理。
Portal
题目大意
- 传送门的位置定义(2):
- 在位置 ( i ) 的传送门,位于数组第 ( i ) 个元素和第 ( i+1 ) 个元素之间。
允许的两种操作
-
操作 1
从一个传送门的紧左边取一个元素,插入到另一个传送门的紧右边。 -
操作 2
从一个传送门的紧右边取一个元素,插入到另一个传送门的紧左边。
目标:
通过任意次这些操作,得到 字典序最小 的排列
代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void so(){
int n,x,y;
cin>>n>>x>>y;
x--;y--;
vector<int>a,b;
for(int i=0;i<n;i++){
int j;cin>>j;
if(i<=x||i>y)a.push_back(j);
else b.push_back(j);
}if(!b.empty())rotate(b.begin(),min_element(b.begin(),b.end()),b.end());
//将b中的最小元素放开头
int m=b.empty()?-1:b[0];
auto it=a.begin();
while(it!=a.end()&&*it<m)it++;
a.insert(it,b.begin(),b.end());
for(int i=0;i<n;i++){
cout<<a[i]<<' ';
}cout<<'\n';
}int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--){so();}
}
思路
1.分成两边和中间
2.中间=最小元素+其他元素顺时针旋转(这点没想到,还以为是拼接)
3.前面的段<m
4.要用两个数组存使代码更简短
stl
这道题用到了两个 C++ STL 算法,我来帮你总结它们的用法和在这道题中的作用。
1. std::rotate 的作用与用法
原型
template< class ForwardIt >
ForwardIt rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );
作用
将区间 [first, last) 内的元素循环左移,使得原来在 n_first 位置的元素成为新的第一个元素。
相当于把 [first, n_first) 的元素移到 [n_first, last) 之后。
2. std::vector::insert 的作用与用法
原型
iterator insert( const_iterator pos, InputIt first, InputIt last );
作用
将 [first, last) 范围内的元素,插入到 pos 位置之前。
返回指向第一个插入元素的迭代器。
Chimpanzini Bananini
题目大意
这道题我来帮你概括一下题意。
有一个数组,初始为空。有三种操作:
- 循环右移:
[a1, a2, ..., an]→[an, a1, a2, ..., an-1] - 反转数组:
[a1, a2, ..., an]→[an, an-1, ..., a1] - 追加元素:在数组末尾添加一个元素 k
每次操作后,需要计算数组的 rizziness:
rizziness = ∑(b[i] * i) (1-indexed)
即每个元素乘以它的位置(从1开始)的总和。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
using ll=long long;
void so(){
int ml=0;
int rev=0;
int q;cin>>q;
int tot=0;
int n=0;
deque<int>qn,qr;
while(q--){
int s;cin>>s;
if(s==1){
int la=qn.back();
qn.pop_back();
qn.push_front(la);//将最后一个弹到开头
ml+=(tot-la);//增量
ml-=la*n;
ml+=la;//出来的
la=qr.front();
qr.pop_front();
qr.push_back(la);
rev-=(tot-la);
rev+=la*n;
rev-=la;
}else if(s==2){
swap(rev,ml);
swap(qn,qr);
}else if(s==3){
n++;
int k;cin>>k;
qn.push_back(k);
qr.push_front(k);
ml+=k*n;
rev+=tot;
rev+=k;
tot+=k;
}cout<<ml<<'\n';
}
}signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--){so();}
}
思路
比起reverse一次的反转,需要n的复杂度重新计算魅力值,一开始就保存反转的数组进行反转
注意保存所有值的总和便于反转
stl
注意deque
push_back()
push_front()
pop_back()
pop_front()