1. 程式人生 > 實用技巧 >[JOISC2020]ビルの飾り付け 4 題解

[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;
}