题目集地址 2021牛客暑期多校训练营2
I 广搜,模拟
题意
两个企鹅走迷宫 左边的企鹅向左,右边的企鹅向右,向上和向下是同步的,有一个企鹅被障碍物挡住后另一个企鹅还可以继续移动,找到两个企鹅都到达终点的最短路径。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=20;
int Next[4][2]= {1,0,0,-1,0,1,-1,0},f[N][N][N][N],g[N][N][N][N];
string a[N],b[N],path;
queue<tuple<int,int,int,int>>Q;
int mirror(int x) {
if(x==1||x==2)
return x^3;
return x;
}
pair<int,int> Move(int x,int y,int i,int m) {
x+=Next[i][0],y+=Next[i][1];
if(m==0&&(x<0||y<0||x>=N||y>=N||a[x][y]=='#'))
x-=Next[i][0],y-=Next[i][1];
if(m==1&&(x<0||y<0||x>=N||y>=N||b[x][y]=='#'))
x-=Next[i][0],y-=Next[i][1];
return {x,y};
}
int main() {
ios::sync_with_stdio(0),cin.tie(0);
for(int i=0; i<N; i++)
cin >>a[i]>>b[i];
Q.emplace(N-1,N-1,N-1,0);
f[N-1][N-1][N-1][0]=1;
while(!Q.empty()) {
auto [x1,y1,x2,y2]=Q.front();
Q.pop();
for(int i=0; i<4; i++) {
auto [nx1,ny1]=Move(x1,y1,i,0);
auto [nx2,ny2]=Move(x2,y2,mirror(i),1);
if(f[nx1][ny1][nx2][ny2]==0) {
f[nx1][ny1][nx2][ny2]=f[x1][y1][x2][y2]+1;
g[nx1][ny1][nx2][ny2]=((((x1*N)+y1)*N+x2)*N+y2)*4+i;
Q.emplace(nx1,ny1,nx2,ny2);
}
}
}
int x1=0,y1=N-1,x2=0,y2=0;
cout <<f[x1][y1][x2][y2]-1<<endl;
while(1) {
a[x1][y1]=b[x2][y2]='A';
if(f[x1][y1][x2][y2]==1)
break;
int G=g[x1][y1][x2][y2];
path+="DLRU"[G%4],G/=4;
y2=G%N;
G/=N;
x2=G%N;
G/=N;
y1=G%N;
G/=N;
x1=G%N;
}
reverse(path.begin(),path.end());
cout <<path<<endl;
for(int i=0; i<N; i++)
cout <<a[i]<<" "<<b[i]<<endl;
return 0;
}
K 栈模拟
题意
已知若干时刻的单调栈大小,构造一个合法的序列
思路
显然对于每一个 b[i],必须满足 b[i]>=i,那么对于未给出数值的 b[i],可以考虑先给它们填充上数值,不妨令 b[i]=b[i-1]+1,这样构造能够满足的条件,随后只需要从后往前构造即可。
从后往前构造时,假如当前b[i]=5,那么最理想的情况下是 a[i]=5,但是可能在前面的构造里已经填充了1,2,3 等值,所以需要用一个树状数组维护前面已经用的值,再二分找到符合条件的最小数值填到当前位置。例如b[i]=5 ,前面已经用了 1,2,那么 ,构造出来的样子就是…7,2,1 。
代码
#include <bits/stdc++.h>
#define maxn int(1e6+1)
using namespace std;
int T[maxn];
int a[maxn],b[maxn];
struct Bit{
int lowbit(int x) {
return x & (-x);
}
Bit() {
memset(T, 0, sizeof(T));
}
void update(int x, int add) { //更新a[x]
while (x < maxn) {
T[x] += add;
x += lowbit(x);
}
}
int sum(int x) { //求前缀和
int res = 0;
while (x) {
res += T[x];
x -= lowbit(x);
}
return res;
}
};
int main()
{
std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
int n,k;
cin >> n >> k;
int f=0;
for(int i = 1;i <= k;i++)
{
int p;
cin >> p;
cin >> b[p];
if(b[p]>p)
{
f = 1;
}
}
if(f)
{
cout << -1 << endl;
return 0;
}
for(int i = 1;i <= n;i++)
{
if(!b[i])
{
b[i]=b[i - 1] + 1;
}
if(b[i]-b[i - 1] > 1)
{
cout << -1 << endl;
return 0;
}
}
Bit Tree;
for(int i = 1;i <= n;i++)
{
Tree.update(i,1);
}
for(int i = n;i >= 1;i--)
{
int l = b[i],r = n;
int ans = l;
int mid;
while(l <= r)
{
mid = (l + r)>>1;
if(Tree.sum(mid) >= b[i])
{
r = mid - 1;
ans = mid;
}
else
{
l = mid + 1;
}
}
a[i] = ans;
Tree.update(ans,-1);
}
for(int i = 1;i <= n;i++)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
拓扑排序方法
#include <iostream>
#include <bits/stdc++.h>
#define maxn int(1e6+1)
using namespace std;
int a[maxn],b[maxn];
queue<int> q;
stack<int> s;
int main()
{
cin.sync_with_stdio(false);
cin.tie(nullptr);
int n,k,f=0;
cin >> n >> k;
while(k--)
{
int id,x;
cin >> id >> x;
b[id]=x;
if(id < x)
{
f = 1;
}
}
if(f)
{
cout << -1 << endl;
return 0;
}
for(int i = 1;i <= n;i++)
{
if(!b[i])
{
b[i] = b[i-1]+1;
}
if(b[i]-b[i - 1] > 1)
{
cout << -1 << endl;
return 0;
}
}
for(int i = 1;i <= n;i++)
{
q.push(i);
}
int sn = 0;
for(int i = n;i >= 1;i--)
{
while(sn < b[i])
{
int t = q.front();
s.push(t);
sn++;
q.pop();
}
a[i] = s.top();
s.pop();
sn--;
}
for(int i = 1;i <= n;i++)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}