1. 程式人生 > 其它 >【題解】#10249. 「一本通 1.3 例 5」weight

【題解】#10249. 「一本通 1.3 例 5」weight

「一本通 1.3 例 5」weight 題解

題意

【題目描述】
原題來自:USACO
已知原數列 \(a_1​,a_2​,\dots,a_n\)​ 中的前 1 項,前 2 項,前 3 項, 前 n 項的和,以及後 1 項,後 2 項,後 3 項,後 n 項的和,但是所有的數都被打亂了順序。此外,我們還知道數列中的數存在於集合 S 中。試求原數列。當存在多組可能的數列時,求字典序最小的數列。

【輸入格式】
第 1 行,一個整數 n 。
第 2 行,2×n 個整數,注意:資料已被打亂。
第 3 行,一個整數 m ,表示 S 集合的大小。
第 4 行, m 個整數,表示 S 集合中的元素。

【輸出格式】
輸出滿足條件的最小數列。

【資料範圍】
對於 100% 的資料, 1≤n≤1000,1≤m≤500 ,且 S∈{1,2,⋯,500} 。

思路

要成為一名合格的OIer,您首先要學會倒著思考。(所謂倒著並不是指倒立):
很明顯,給定了和的集合後,加以排序,每個位置上的數都確定了。故用深搜找出符合條件的數列即可。
對於每一個被拎出來的數,它只有可能被放在數列的前半段(順著搜)或後半段(倒著搜)。於是我們在dfs函式中用兩個引數xy記錄分別順著/倒著搜到哪,當x==y且剩下待填入的數在數集S裡時,說明找到了目標數列,輸出即可。
字典序?暫時不會證[笑哭],持續更新……

順便說一句,筆者在理解題解的時候有如下抽風行為:

  1. \(S_n\)=\(T_n\), 即字首和與字尾和中,各自的最大值相等
    很明顯,數列\(a_1, a_2 , \dots ,a_n\)一共有\(n\)項。


看起來很棒,但是不能滿足字典序最小。
為什麼?其實筆者還不知道。

程式碼實現

x. seq1[p1]=0
最後一道關卡:下載大樣例後發現總是有一處輸出0,逐段排查後發現是回溯時加上seq[p]=0這一句導致的。但是按理說,已經回溯了,不影響呀?
究其原因,是不太聰明的筆者把seq[p]=0放在了p--後面……直接導致了RE和WA……這個故事告訴我們,做題的時候要集中精力!不要邊聽信(y)息(z)老(j)師催眠邊寫,除非您有足夠的時間、精力和耐心找這個低階錯誤。

♪(^∀^●)ノ撒花~

AC Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2005;
int n,m;
ll s[N];
ll p,seq1[N],p1,seq2[N],p2;
bool a[N],flag;

void dfs(int k,int x,int y,ll pre,ll suf) {
	if(flag) return;
	if(x==y) {
		if((!a[s[k]-pre]) && (!a[s[k]-suf])) return;
		if(s[2*n]<=suf+pre || s[2*n]-pre-suf>500) return;
		if(!a[s[2*n]-suf-pre]) return;
		for(int i=1; i<=p1; i++) printf("%lld ",seq1[i]);
		printf("%lld ",s[2*n]-suf-pre);
		for(int i=p2; i>=1; i--) printf("%lld ",seq2[i]);
		flag=true;
		return;
	}
	if(s[k]>pre && s[k]-pre<=500) {
		if(a[s[k]-pre]) {
			p1++;
			seq1[p1]=s[k]-pre;
			dfs(k+1,x+1,y,s[k],suf);
			if(flag) return;
			p1--;
		}
	}
	if(s[k]>suf && s[k]-suf<=500) {
		if(a[s[k]-suf]) {
			p2++;
			seq2[p2]=s[k]-suf;
			dfs(k+1,x,y-1,pre,s[k]);
			if(flag) return;
			p2--;
		}
	}
}

int main() {
	scanf("%d",&n);
	for(int i=1; i<=2*n; i++) scanf("%lld",&s[i]);
	scanf("%d",&m);
	for(int i=1,j; i<=m; i++) {
		scanf("%d",&j);
		a[j]=true;
	}
	sort(s+1,s+2*n+1);
	dfs(1,1,n,0,0);//the first element of set a,now filling the yth space,current sum
	return 0;
}
/*
5
1 2 5 7 7 9 12 13 14 14
4
1 2 4 5
*/
//2022.03.03,finally!!!!!!!