「JOISC 2020 Day1」建筑装饰 4
传送门
题解
考虑设(f_{i,j,k})表示到了第(i)个位置,用了(j)个A
,(k)个B
的可行性,打表发现对于((i,j))的(k)是连续的,所以考虑记录:
(l_{i,j})表示前(i)个位置用了(j)个A
最少用多少个B
,(r_{i,j})同理.
最后输出方案的时候一步一步的倒推即可.
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define REP(a,b,c) for(int a=b;a<=c;a++)
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
typedef pair<int,int> pii;
#define mp make_pair
inline int gi()
{
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
const int N=1000010,Inf=1e9+10;
int a[N],b[N],f[N][2],g[N][2],n;
void dfs(int id,int ex,int c)
{
if(!id)return;
if(f[id-1][0]<=ex&&g[id-1][0]>=ex&&a[id-1]<=(c?b[id]:a[id]))
dfs(id-1,ex,0);
else dfs(id-1,ex-1,1);
putchar(c+'A');
}
int main()
{
n=gi();
for(int i=1;i<=n<<1;i++)a[i]=gi();
for(int i=1;i<=n<<1;i++)b[i]=gi();
f[1][0]=g[1][0]=0;
f[1][1]=g[1][1]=1;
for(int i=2;i<=n<<1;i++)
{
f[i][0]=f[i][1]=Inf;
g[i][0]=g[i][1]=-Inf;
if(a[i]>=a[i-1])
{
f[i][0]=min(f[i][0],f[i-1][0]);
g[i][0]=max(g[i][0],g[i-1][0]);
}
if(a[i]>=b[i-1])
{
f[i][0]=min(f[i][0],f[i-1][1]);
g[i][0]=max(g[i][0],g[i-1][1]);
}
if(b[i]>=a[i-1])
{
f[i][1]=min(f[i][1],f[i-1][0]+1);
g[i][1]=max(g[i][1],g[i-1][0]+1);
}
if(b[i]>=b[i-1])
{
f[i][1]=min(f[i][1],f[i-1][1]+1);
g[i][1]=max(g[i][1],g[i-1][1]+1);
}
}
if(!((f[n<<1][0]<=n&&g[n<<1][0]>=n)||(f[n<<1][1]<=n&&g[n<<1][1]>=n)))puts("-1");
else
{
if(f[n<<1][0]<=n&&g[n<<1][0]>=n)dfs(n<<1,n,0);
else dfs(n<<1,n-1,1);
}
puts("");
return 0;
}