计数 & 最优化做题记录

\(\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\)):

  1. 所选歌曲 \(x_{1\sim j}\) 满足 \(\sum\limits_{k=1}^jB_{x_k}=sum\)
  2. \(\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';
}
posted @ 2025-11-03 07:40  LXcjh4998  阅读(6)  评论(0)    收藏  举报