计数 & 最优化做题记录
\(\text{Problems}\)
\(\text{Problem}1\text{ ABC}424\text{G (}2413\text{)}\)
有 \(n\) 个人和 \(m\) 个节目,第 \(i\) 个人最多参加 \(A_i\) 个节目,第 \(i\) 个节目需要 \(B_i\) 个人,分数为 \(C_i\)。
每个节目最多选一次。
求出满足所有的条件的方案中,分数之和的最大值。
保证 \(1\le n,m\le100,0\le A_i\le m,0\le B_i\le n,0\le C_i\le10^9\)。
\(\text{Time Limit }2\text{s},\text{Memory Limit }1024\text{MB}\)。
$\text{Hint}$
若已经确定了所选的节目,如何判定是否存在分配的方案?
找到存在方案的充要条件。
$\text{Tutorial}$
若把选择的节目按 \(B\) 不升排序,设此时得到的序列为 \(B'\),长度为 \(N\)。
则存在分配的方案,当且仅当 \(\forall 1\le i\le N,\sum\limits_{k=1}^n\min(A_k,i)\ge\sum\limits_{k=1}^iB'_k\)。
$\text{Proof}$
先证充分性。
考虑证明其逆否命题。
若存在一个 \(i\),使得条件不满足。
那么对于节目 \(B'_{1\sim i}\),没有足够的次数分配给它们,因此不存在满足的方案。
再证必要性。
对 \(N\) 使用归纳法。
首先 \(N=1\) 时随便分配。
若 \(N\ge 2\),我们先把人按 \(A_i\) 不升排序,此时得到的序列记为 \(A'\)。
把人 \(A'_{1\sim B'_1}\) 都分配给节目 \(B'_1\),记 \(A''\) 为经这一轮分配,每个人剩下的可分配节目数。
对于分配了节目的人,有 \(\min(A''_k,N-1)=\min(A'_k,N)-1\)。
若对于任意没有分配节目的人,都有 \(A''_k<N\),则对于他们有 \(\min(A''_k,N-1)=A''_k=\min(A'_k,N)\)。
此时有 \(\sum\limits_{k=1}^n\min(A''_k,N-1)=\sum\limits_{k=1}^n\min(A'_k,N)-B'_1\ge\sum\limits_{k=2}^NB'_k\)。
若存在没有分配节目的人,使得 \(A''_k\ge N\),则对于任意的分配了节目的人,有 \(\min(A'_k,N)-1=N-1\)。
此时有 \(\sum\limits_{i=1}^n\min(A''_i,N-1)\ge B'_1(N-1)\ge\sum\limits_{k=2}^NB'_k\)。
因此,无论如何有 \(\sum\limits_{i=1}^n\min(A''_i,N-1)\ge\sum\limits_{k=2}^NB'_k\)。
根据归纳假设,后面 \(N-1\) 个节目一定存在一种分配方案。
因此一定存在一种分配方案。
注意到选择 \(i\) 个节目最多能分配的次数 \(\lim_i=\sum\limits_{k=1}^n\min(A_k,i)\) 是固定的。
然后我们可以先对 \(B\) 进行降序排序,因此下文默认 \(B\) 为降序的(\(B\) 和 \(C\) 将一同被排序)。
设 \(dp_{i,j,sum}\) 为在 \(B_{1\sim i}\) 中选择 \(j\) 首,并且满足以下 \(2\) 个条件的能获得的最大分数(若一定无法满足,则为 \(-\infty\)):
- 所选歌曲 \(x_{1\sim j}\) 满足 \(\sum\limits_{k=1}^jB_{x_k}=sum\)。
- \(\forall 1\le k'\le j,\sum\limits_{k=1}^{k'}B_{x_k}\le lim_{k'}\)。
有初值 \(dp_{0,j,sum}=\begin{cases}0&,j=sum=0\\ -\infty &,\text{otherwise}\end{cases}\)。
有转移 \(dp_{i,j,sum}=\begin{cases}-\infty&,sum>lim_j\\ dp_{i-1,j,sum}&,sum<B_i\\ \max(dp_{i-1,j,sum},dp_{i-1,j-1,sum-B_i}+C_i)&,\text{otherwise}\end{cases}\)。
答案为 \(ans=\max\limits_{0\le j\le m,0\le sum\le n*m}dp_{n,j,sum}\)。
时间复杂度 \(O(nm^3)\),空间复杂度 \(O(nm^2)\)。
$\text{Solution}$
#define forUp(i,a,b) for(int i=(a);i<=(b);++i)
using int64=long long;
constexpr int MINF=0xcfcfcfcf;constexpr int64 MINF64=0xcfcfcfcfcfcfcfcf;
template<class _Tp>inline void chkMax(_Tp &x,const _Tp &y){x<y?x=y:0;}
constexpr int N=100+10,S=10000+10;
int n,m,A[N];array<int,2> B[N];
int lim[N];int64 dp[2][N][S],ans;
void solve(){
cin>>n>>m;
forUp(i,1,n)cin>>A[i];
forUp(i,1,m)cin>>B[i][0]>>B[i][1];
sort(B+1,B+m+1,greater<array<int,2>>());
forUp(i,1,m)forUp(j,1,n)lim[i]+=min(A[j],i);
memset(dp,MINF,sizeof(dp));dp[0][0][0]=0;
int cur=0,pre=1;
forUp(i,1,m){
cur^=1,pre^=1;
forUp(j,0,i)forUp(sum,0,n*m){
if(sum>lim[j]){
dp[cur][j][sum]=MINF64;
continue;
}
dp[cur][j][sum]=dp[pre][j][sum];
if(sum>=B[i][0]&&j>=1)chkMax(dp[cur][j][sum],dp[pre][j-1][sum-B[i][0]]+B[i][1]);
}
}
forUp(j,0,m)forUp(sum,0,n*m)chkMax(ans,dp[cur][j][sum]);
cout<<ans;
}
\(\text{Problem}2\text{ AThitachi}2020\text{D (}2437\text{)}\)
$\text{Solution}$
#define forUp(i,a,b) for(int i=(a);i<=(b);++i)
constexpr int INF=0x3f3f3f3f;
template<class _Tp>inline void chkMax(_Tp &x,const _Tp &y){if(x<y)x=y;}
constexpr int N=2e5+10,M=31+10;
int n,V,n1,n2,A[N],B1[N],B2[N];
int sorted[N],dp[N][M];
void solve(){
cin>>n>>V;
forUp(i,1,n){
int a,b;cin>>a>>b;++a;
if(a==1)B2[++n2]=b;
else A[++n1]=a,B1[n1]=b;
}
forUp(i,1,n1)sorted[i]=i;sort(sorted+1,sorted+n1+1,[&](int i,int j)->bool{return (A[i]-1ll)*(B1[j]+1)>(A[j]-1ll)*(B1[i]+1);});
forUp(j,1,31)dp[0][j]=INF;
forUp(k,1,n1){
int i=sorted[k];
forUp(j,1,31){
dp[k][j]=dp[k-1][j];
if(A[i]*(dp[k-1][j-1]+1ll)+B1[i]<=V)chkMin(dp[k][j],A[i]*(dp[k-1][j-1]+1)+B1[i]);
}
}
sort(B2+1,B2+n2+1);forUp(i,1,n2)B2[i]+=B2[i-1]+1;
int ans=0;
forUp(k,0,31)if(dp[n1][k]<=V){
int res=max((int)(upper_bound(B2+1,B2+n2+1,V-dp[n1][k])-B2-1),0);
chkMax(ans,res+k);
}
cout<<ans<<'\n';
}

浙公网安备 33010602011771号