P9339 [JOISC 2023] Cookies (Day3) 题解

· · 题解

先假装我们知道了盒子有 k 个和对应的容量 c_1\dots c_k,建立一个类似网络流的二分图:对于第 i 种饼干,建边 S\xrightarrow{a_i}i;对于第 i 个盒子,建边 i\xrightarrow{c_i}T;每个饼干向每个盒子连容量为 1 的边。

考虑 Hall 定理,有一种合法方案当且仅当 \sum a=\sum c 并且对于每个盒子集合 S\sum_{i\in S}c_i\le \sum_{i=1}^n\min(a_i,|S|),这个取 \min 是因为如果某个 a_i>|S| 的话,这个点集大小是假的,根本不可能。

然后考虑某一个盒子集合 S,把 S 中的所有数换成 c 的前 |S| 大变成 S',显然 S' 的限制是更强的,即如果 S' 的限制被满足,那么 S 就会被满足,因此在把盒子从大到小排序之后,我们只需满足这个序列每个前缀的限制。

于是转化为,找到存在满足条件的序列 c 的最小长度 kc 中的元素递减,c_i\in B,对于 c 的每个长 j 的前缀,都要满足 \sum_{i=1}^jc_i\le \sum_{i=1}^n\min(a_i,j)\sum c=\sum a

B 从大到小排序,设 f_{i,j,k} 表示考虑 B 中前 i 个元素,已经选了 j 个,\sum c=k 是否可行。

f_{i,j,k}\to f_{i,j+1,k+b_i}\\ f_{i,j,k}\to f_{i+1,j,k} \end{cases} 对于构造方案,首先找出所有箱子的容量 $c_1\dots c_k$,考虑从大往小删除然后归纳,每次让限制尽可能松,发现需要让 $\sum\min(a_i,j)$ 尽可能大,所以每次匹配一些最大的 $a$ 即可。 ```cpp #define maxn 15010 int n,m; int a[maxn],b[maxn],c[maxn]; vector<bitset<maxn>>f[maxn]; int cf[maxn]; signed main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n; rep(i,1,n)cin>>a[i]; rep(i,1,n)cf[a[i]+1]+=1; cin>>m; rep(i,1,m)cin>>b[i]; int sum=accumulate(a+1,a+n+1,0); sort(b+1,b+m+1,greater<int>()); f[0].resize(1); f[0][0][0]=1; int ans=inf; bitset<maxn>tmp; d(sum),ce; rep(i,1,m) { int lim=sum/b[i]+1; f[i].resize(lim+2); int lst=f[i-1].size(); rep(j,0,lst-1)f[i][j]=f[i-1][j]; int C=n,pre=0; tmp.reset();tmp[0]=1; auto &F=f[i]; rep(j,0,lim) { C-=cf[j+1]; rep(t,pre+1,pre+C)tmp[t]=1; pre+=C; F[j+1]|=(F[j]<<b[i]); F[j+1]&=tmp; } rep(j,0,lim+1)if(F[j][sum])ckmin(ans,j); } if(ans==inf){ cout<<"-1\n"; return 0; } cout<<ans<<'\n'; per(i,m,1){ if((int)f[i].size()>ans&&f[i][ans][sum]){ auto dfs=[&](auto&self,int i,int j,int s)->void{ if(i==0)return; c[j]=b[i]; if(j>=0&&s>=b[i]&&f[i][j-1][s-b[i]])self(self,i,j-1,s-b[i]); else self(self,i-1,j,s); }; dfs(dfs,i,ans,sum); break; } } priority_queue<pii>p; rep(i,1,n)p.push({a[i],i}); rep(i,1,ans){ cout<<c[i]<<" "; vector<pii>vec; rep(j,1,c[i]){ pii t=p.top();p.pop(); cout<<t.se<<" "; if(t.fi>1)vec.push_back({t.fi-1,t.se}); } for(pii t:vec)p.push(t); cout<<'\n'; } return 0; } ```