【大模拟】

【大模拟】

锻炼码力!

兢兢业业之移

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;
}
posted @ 2025-01-23 12:40  White_ink  阅读(16)  评论(0)    收藏  举报