AtCoder Beginner Contest 270

D

贪心是错的,考虑 dp。
\(dp[i]\) 表示还剩 \(i\) 个石子,先手走能取到的最大石子数。
转移:\(dp[i]=\max(dp[i],i-dp[i-a[j]])\)
其中 \(j\) 为枚举的本轮取几个石子。

感觉这个 dp 挺不好想的,以后对于这种博弈 dp 的方程要敏感。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int n,k,a[N],f[N];
signed main()
{
	cin>>n>>k;
	for(int i=1;i<=k;++i)cin>>a[i];
	for(int i=1;i<=n;++i)
		for(int j=1;j<=k;++j)
			if(i-a[j]>=0)f[i]=max(f[i],i-f[i-a[j]]);	
	cout<<f[n];
	return 0;
}

E

看到 \(k\) 这么大,容易想到二分。
二分能取多少整轮,对于多余的部分模拟即可。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n,k,a[N],cnt[N];
bool check(int mid)
{
	int res=0;
	for(int i=1;i<=n;++i)
		if(a[i]>mid)res+=mid;
		else res+=a[i];
	return res<=k;
}
signed main()
{
	cin>>n>>k;
	for(int i=1;i<=n;++i)cin>>a[i];
	int l=0,r=k+1;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(check(mid))l=mid;
		else r=mid-1;
	}
	int res=0;
	for(int i=1;i<=n;++i)
	{
		if(a[i]>l)res+=l;
		else res+=a[i];
		a[i]=max(a[i]-l,0ll);
	}
	res=k-res;
	for(int i=1;i<=n;++i)
	{
		if(res==0)break;
		if(a[i])res--,a[i]--;
	}
	for(int i=1;i<=n;++i)
		cout<<a[i]<<" ";
	return 0;	
} 
posted @ 2022-10-02 11:33  lnwhl  阅读(29)  评论(0编辑  收藏  举报