[JOISC2020]ビルの飾り付け 4 题解
考虑 \(\text{DP}\)。
从第一个条件得知,第一维要记录当前处理到的数字的位置 \(i\)。
从第二个条件得知,第二维要记录选取的 \(A\) 或 \(B\) 的数量 \(j\)。
从第三个条件得知,第三维要记录当前选的是 \(A\) 还是 \(B\)。可以用 \(0/1\) 表示。
所以有了 \(\text{40pts}\) 做法:
令 \(f_{i,j,0/1}\) 表示当前处理到第 \(i\) 位,前面选取了 \(j\) 个 \(B\) 中的数,并且当前位置选择的是 \(A/B\) 是否可行。
考虑优化。似乎一般的优化转移都不可做,所以我们选择优化状态。
将暴力的数据输出,发现对于每个固定的 \(i\) 和 \(0/1\),可行的 \(j\) 都是连续的。
所以我们不用记录可行性而改为记录可行的左右端点。
令 \(f_{i,0/1}\) 表示当前处理到第 \(i\) 位,并且当前位置选择的是 \(A/B\) 的 \(B\) 的数量的上下界。
可以使用 \(\text{pair}\) 存储。转移只要四个判断即可完成。
还原出答案只需倒着循环一遍即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(register int i=a;i<=b;++i)
#define Rep(i,a,b) for(register int i=a;i>=b;--i)
inline int read()
{
bool f=0;int x=0;char ch;
do{ch=getchar();f|=(ch=='-');}while(!isdigit(ch));
do{x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}while(isdigit(ch));
return f?-x:x;
}
inline void write(int x)
{
if(x<0)x=-x,putchar('-');
if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writesp(int x)
{
write(x);putchar(' ');
}
inline void writeln(int x)
{
write(x);puts("");
}
const int maxn=1e6+5;
int a[maxn],b[maxn];
pair<int,int> f[maxn][2];
void upd(pair<int,int> &x,pair<int,int> y){
x.first=min(x.first,y.first);
x.second=max(x.second,y.second);
}
int main()
{
int n=read();
rep(i,1,n<<1)a[i]=read();
rep(i,1,n<<1)b[i]=read();
f[0][0]=f[0][1]=make_pair(0,0);
rep(i,1,n<<1)
{
f[i][0]=f[i][1]=make_pair(INT_MAX,INT_MIN);
if(a[i-1]<=a[i])f[i][0]=make_pair(min(f[i-1][0].first,f[i][0].first),max(f[i-1][0].second,f[i][0].second));
if(b[i-1]<=a[i])f[i][0]=make_pair(min(f[i-1][1].first,f[i][0].first),max(f[i-1][1].second,f[i][0].second));
if(a[i-1]<=b[i])f[i][1]=make_pair(min(f[i-1][0].first,f[i][1].first),max(f[i-1][0].second,f[i][1].second));
if(b[i-1]<=b[i])f[i][1]=make_pair(min(f[i-1][1].first,f[i][1].first),max(f[i-1][1].second,f[i][1].second));
++f[i][1].first;++f[i][1].second;
}
int qaq=114514;
if(f[n<<1][0].first<=n&&n<=f[n<<1][0].second)
{
qaq=0;
}
if(f[n<<1][1].first<=n&&n<=f[n<<1][1].second)
{
qaq=1;
}
if(qaq==114514)
{
puts("-1");return 0;
}
stack<char> ans;
int rest=n;
Rep(i,n<<1,1)
{
ans.push(qaq?'B':'A');
rest-=qaq;
int cur=(qaq?b[i]:a[i]);
if(a[i-1]<=cur&&f[i-1][0].first<=rest&&f[i-1][0].second>=rest)qaq=0;
else qaq=1;
}
while(!ans.empty()){putchar(ans.top());ans.pop();}
return 0;
}
我好菜啊。——ฅ(OωO)ฅ