【大模拟】
【大模拟】
锻炼码力!
兢兢业业之移
https://ac.nowcoder.com/acm/contest/95323/C
推箱子问题 注意许多细节
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=110;
int t;
int n;
string s[N];
//lambda函数一般用来简化操作:直接引用就可以直接修改值
/*auto name=[]()->type{};*/
void solve(){
cin>>n;
//因为string也是从0开始:从0读入会更方便
for(int i=0;i<n;i++) cin>>s[i];
//存几元组的时候就用array
vector<array<int,4>> ans;
auto work=[&](int x1,int y1,int x2,int y2){
swap(s[x1][y1],s[x2][y2]);
ans.push_back({x1+1,y1+1,x2+1,y2+1});
};
//把(a1,b1)挪到(a2,b2)
auto move=[&](int x1,int y1,int x2,int y2){
//x方向上挪动
auto movex=[&](){
while(x1<x2){
work(x1,y1,x1+1,y1);
x1++;
}
while(x1>x2){
work(x1,y1,x1-1,y1);
x1--;
}
};
auto movey=[&](){
while(y1<y2){
work(x1,y1,x1,y1+1);
y1++;
}
while(y1>y2){
work(x1,y1,x1,y1-1);
y1--;
}
};
/*移动顺序:【不干扰之前挪好的点 在非区间里挪】
目标点在待移点下面:先挪下再挪左 (先左再下 会干扰到之前已经挪好的左边点
目标点在待移点上面:先挪左再挪下
*/
if(x1>=x2){
movey();
movex();
}
else{
movex();
movey();
}
};
//依次遍历每个目标点 找当前最近的1走一遍
int x=0,y=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
while(s[i][j]=='1'){//需要连续处理:如果移动过程中有1相邻就需要处理好几次
move(i,j,x,y);
s[x][y]='2';//表示已经处理过该点
y++;
if(y==n/2){
y=0;
x++;
}
}
}
}
int res=ans.size();
cout<<res<<endl;
for(auto [a,b,c,d]:ans){
cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
solve();
}
return 0;
}
Pigeon Swap
https://atcoder.jp/contests/abc395/tasks/abc395_d
思路
并查集 set map都不需要->会TLE
搞清楚各个量及其对应关系即可
代码
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int n,qq;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>qq;
vector<int> a(n+1),q(n+1),p(n+1);
/*
【模拟移动问题】 搞清楚下标和值的对应关系:
鸟:只有编号 下标无意义
巢穴:巢穴结点 和 巢穴编号 对应关系(对比链式前向星中的idx)
a:下标 鸟编号 值 鸟所在的巢穴结点
q:下标 巢穴结点 值 巢穴编号
p:下标 巢穴编号 值 巢穴结点
*/
for(int i=1;i<=n;i++) a[i]=i,q[i]=i,p[i]=i;
while(qq--){
int op;
cin>>op;
if(op==1){
//鸟挪动到某巢穴
int x,y;
cin>>x>>y;//y是巢穴编号
a[x]=p[y];//挪巢穴结点即可
}
else if(op==2){
//交换巢穴编号
int x,y;
cin>>x>>y;
swap(p[x],p[y]);//编号交换节点
swap(q[p[x]],q[p[y]]);//节点交换编号
}
else if(op==3){
int x;
cin>>x;
//依据巢穴结点查询巢穴编号
cout<<q[a[x]]<<endl;
}
}
return 0;
}
Dining Hall
https://codeforces.com/contest/2090/problem/C
用bfs模拟走走廊的过程
并用priority_queue依次取出座位x和y
注意struct中运算符重载的大小于号相反
//bfs模拟,优先队列维护可选择的桌子和椅子
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int T;
int n;
//注意到走廊全是n%3==0的
struct node{
int x,y,d;//d表示距离
friend bool operator < (node a,node b){
//注意这里运算符重载 外面是< 里面要写>!!!
if(a.d!=b.d) return a.d>b.d;
if(a.x!=b.x) return a.x>b.x;
return a.y>b.y;
}
};
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
//注意一个小细节:距离是根据走廊距离算的!不是到原点的距离也不是欧拉距离!
void solve(){
cin>>n;
vector<int> t(n+1);
for(int i=1;i<=n;i++) cin>>t[i];
map<PII,int> st,st_zhuo;//bfs中st数组:记一个全局的 记一个每个桌子是不是被占了的
priority_queue<node> wei,zhuo;
queue<node> q;//bfs用
q.push({0,0,0});
//预处理部分
while(q.size()){
auto [x,y,dd]=q.front();
q.pop();
//最多n个
if(zhuo.size()>=n && wei.size()>=n) break;
if(x%3!=0 && y%3!=0){//结论
st[{x,y}]=1;
//位置直接推进
wei.push({x,y,dd});
//判断在哪个桌子:直接 /3
int zx=x/3,zy=y/3;
if(!st_zhuo[{zx,zy}]){
st_zhuo[{zx,zy}]=1;
zhuo.push({zx,zy,dd});
}
continue;
}
//以走廊为长度来进行拓展
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx<0 || ny<0) continue;
if(st[{nx,ny}]) continue;
st[{nx,ny}]=1;
q.push({nx,ny,dd+1});
}
}
//按照题目所给表一个一个取出
map<PII,int> used_zhuo,used_wei;
for(int i=1;i<=n;i++){
if(t[i]==0){//空桌子
while(used_zhuo[{zhuo.top().x,zhuo.top().y}]) zhuo.pop();
//取出最近的空桌子
auto [x,y,dd]=zhuo.top();
zhuo.pop();
used_zhuo[{x,y}]=1;
//桌子坐标要记得转化!
int xx=x*3+1,yy=y*3+1;
cout<<xx<<" "<<yy<<endl;
//位置记得也要标记
used_wei[{xx,yy}]=1;
}
else{//空位置
while(used_wei[{wei.top().x,wei.top().y}]) wei.pop();
auto [x,y,dd]=wei.top();
wei.pop();
used_wei[{x,y}]=1;
cout<<x<<" "<<y<<endl;
int xx=x/3,yy=y/3;
used_zhuo[{xx,yy}]=1;
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--) solve();
return 0;
}
Sharky Surfing
https://codeforces.com/contest/2037/problem/D
注意可能会有增益点横跨多个障碍区间(不只是一个!)的情况->要while
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef pair<ll,ll> PII;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int n,m;
ll l;
void solve(){
cin>>n>>m>>l;
vector<PII> f;
for(int i=1;i<=n;i++){
ll L,R;
cin>>L>>R;
PII temp={L,R};
f.push_back(temp);
}
//双指针找左端点前 能不能满足条件 贪心 优先队列:选肯定是选大的 能满足条件就不选
vector<PII> ad;
for(int i=1;i<=m;i++){
ll U,V;
cin>>U>>V;
ad.push_back({U,V});
}
ad.push_back({l,0});
int j=0;
int ans=0;
ll sum=1;
priority_queue<ll,vector<ll>,less<ll>> d;
for(int i=0;i<=m&&j<n;i++){
//cout<<ad[i].first<<endl;
//可能连跨多个区间:while
while(j<n && ad[i].first>=f[j].first){//当前已经截止:清空优先队列
//while(i<m&&ad[i].first<=f[j].second) i++;
while(f[j].first-1+sum<=f[j].second && d.size()){
ll ttt=d.top();
//cout<<ttt<<endl;
sum+=ttt;
d.pop();
ans++;
}
if(f[j].first-1+sum<=f[j].second){
cout<<"-1"<<endl;
return;
}
j++;
}
d.push(ad[i].second);
}
//cout<<j<<endl;
if(j<n){
cout<<"-1"<<endl;
return;
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T;
cin>>T;
while(T--) solve();
return 0;
}

浙公网安备 33010602011771号