题解: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;
}

浙公网安备 33010602011771号