題解 P6345 [CCO 2017]接雨滴

Varuxn發表於2021-11-18

解題思路

NOIP在即,感覺即將退役,或許是最後一篇題解了。。。

求水的體積不是特別好求,我們考慮求出 水+柱子 的體積最後再減去柱子的體積。

發現對於最高的柱子在中間的情況其實可以把最高柱子一側的柱子平移到另一邊,其實是一樣的,類似於下圖的這種情況:

由於我們計算的是 水+柱子 的體積,因此對於一個位置 \(pos\) 它有意義當且僅當它比他左邊或者右邊的柱子高。

同時根據上圖,我們可以發現其實所有柱子和水的體積之和就是兩個次高柱子的高度。

那麼我們可以先將所有的柱子從小到大列舉,每次插入一個次小值,然後列舉插入這個柱子後可以構成幾個 水+柱子 的體積是這樣高度的格子。

一個類似於揹包的東西直接 bitset 維護即可。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=5e2+10,M=25e3+10;
int n,cnt,sum,s[N];
bitset<M> bit[N],ans;
#undef int
int main()
{
	#define int long long
	freopen("drop.in","r",stdin); freopen("drop.out","w",stdout);
	n=read(); for(int i=1;i<=n;i++) s[i]=read(),sum+=s[i]; ans[sum]=true;
	sort(s+1,s+n+1,greater<int>()); bit[1][s[1]]=true;
	for(int i=2;i<=n;i++) bit[i]|=bit[i-1]<<s[2];
	for(int i=3;i<=n;i++) if(s[i]!=s[i-1])
	{for(int j=i;j<=n;j++) bit[j]|=bit[j-1]<<s[i];ans|=bit[n];}
	for(int i=sum;i<=M-10;i++) if(ans[i]) printf("%lld ",i-sum);
	return 0;
}

相關文章