题解:P14011 [POCamp 2023] 珿求 / bootfall

更差的阅读体验


首先,我们预处理出 \(f_i\) 表示当进攻能力为 \(i\) 时防守能力最大能有多少。

对于一组询问,假设我们派出的进攻、防守兵力分别为 \(a,d\),对方分别为 \(a',d'\)。那么我们考虑己方和对方进球 \(\max(0, a-d')\)\(\max(0, a'-d)\)。由于我们只需要考虑自己赢或打平的情况,因此可以分以下三种情况考虑:

  • \(a-d' \le 0\)。则此时不妨直接让 \(a = 0\),这样 \(d\) 尽可能大,可以让 \(a' - d\) 尽可能小。如果 \(a' - d \le 0\),则有可能打平。
  • \(a-d' > 0, a' -d\le 0\)。则把 \(d\) 换成 \(f_{a}\),有 \(a' - f_a \le 0\)。我们预处理出 \(f\) 的后缀最大值就能判断。
  • \(a-d' > 0, a' -d> 0\)。则还是把 \(d\) 换成 \(f_{a}\),有 \(a-d' > a'-f_a, a+f_a > a' + d'\)。因此只要预处理出 \(f_a + a\) 的后缀最大值就能判断。

预处理 \(f\) 直接背包。那么这道题就做完了,复杂度 \(O(n^3 + q)\)

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define N 406
using namespace std;
int n,q,a[N],b[N],f[2][N*N],g[N*N],h[N*N],sa,sb;
int win,lose,draw;
main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld%lld",&a[i],&b[i]),sa+=a[i];
	memset(f,-0x3f,sizeof(f)),f[0][0]=0;
	for(int i=1;i<=n;i++)
	{
		f[i&1][0]=(sb+=b[i]);
		for(int j=0;j<=sa;j++)
		{
			f[i&1][j]=f[(i&1)^1][j]+b[i];
			if(a[i]<=j)f[i&1][j]=max(f[i&1][j],f[(i&1)^1][j-a[i]]);
		}
	}
	for(int i=0;i<=sa;i++)g[i]=i+f[n&1][i];
	for(int i=sa;~i;i--)
		h[i]=max(h[i+1],f[n&1][i]),g[i]=max(g[i+1],g[i]);
	scanf("%lld",&q);
	while(q--)
	{
		int x,y;scanf("%lld%lld",&x,&y);
		int w=0,d=0;
		if(x-f[n&1][0]<=0)d++;
		if(h[y+1]>x)w++;
		else {
			if(h[y+1]==x)d++;
			if(g[y+1]>x+y)w++;
			else if(g[y+1]==x+y)d++;
		}
		if(w)win++;
		else if(d)draw++;
		else lose++;
	}
	printf("%lld %lld %lld\n",win,draw,lose);
	return 0;
}
posted @ 2025-09-10 18:02  dyc2022  阅读(48)  评论(0)    收藏  举报
/* 设置动态特效 */ /* 设置文章评论功能 */ 返回顶端 levels of contents