P7986 [USACO21DEC] HILO P 题解
本篇文章翻译自官方题解。由于笔者考场上没有通过此题,如有不当之处,还请在评论区指出。
还有这里因该比 Gold 那题难不少吧,建议评紫(?。
Suppose that we have already constructed some prefix of the permutation, and there are
j remaining non-redundant values below Bessie's number andk remaining non-redundant values above Bessie's number (we define non-redundant numbers as numbers that Elsie could guess that would give her more information). Also, consider the two cases where Bessie has most recently said either "HI" or "LO". Letb=0 be the case where Bessie has most recently said "LO" and letb=1 be the case where Bessie has most recently said "HI". Then, the expected number of "HILO"s for the original problem is just the case wherej=x, k=N-x, b = 0 .
考虑 dp 状态,假设我们已经算到了某个位置,并且剩余了 LO,HI。这样的话,HILO出现的期望次数就是
Thus, it is sufficient to count the expected number of "HILO"s for each
j \leq x, k \leq N-x, andb = 0 orb=1 . Call this quantitydp[b][j][k] . Now, note that all redundant values do not affect the expected number of "HILOs", so we ignore all of them. Then, there arej+k possible values for the next number in the permutation, each of which occurs with probability\frac{1}{j+k} .
因而,我们只需对每个 HILO出现的期望次数。定义状态为
We will first consider the case where
b=0 . Suppose that the next value in th.e permutation is less thanx+0.5, of which there arej possibilities. Denote these values asv_0, v_1, v_2, \cdots v_{j-1} such thatx+0.5 > v_0 > v_1 > v_2 \cdots > v_{j-1} .
首先考虑
Suppose the next value in the permutation is
v_{j_2} for some0 \leq j_2 < j . Then, Bessie says "LO" (becausev_{j_2} < x+0.5 ) and there arej_2 remaining nonredundant values below Bessie's number. Thek initial nonredundant values above Bessie's number are still nonredundant, so the expected number of HILOs in the remaining sequence of values isdp[0][j_2][k] .
设再往下的一个数为 LO因为HILO的出现次数就是
Similarly, if we consider the values greater than
x+0.5, which we labelx+0.5 < u_0 < u_1 < u_2 \cdots < u_{k-1}, if we choose one of these valuesu_{k_2} , Bessie says "HI" and there arek_2 remaining nonredundant values above Bessie's number, so the expected number of HILOs in the remaining sequence of values isdp[1][j][k_2] .
相似地,如果我们考虑的值是比 HI,并剩下 HILO的出现次数就是
So, we have the recurrence
dp[0][j][k] = \frac{\sum_{j_2 < j} dp[0][j_2][k] + \sum_{k_2 < k} dp[1][j][k_2]}{j+k} .
因此,我们得到转移方程
For computing
dp[1][j][k], we can apply the same technique. However, since Bessie has just said "HI", if we now choose a valuev_{j_2} < x+0.5, Bessie will then say "LO" and the number of "HILO"s increases by one. We choose a value less thanx+0.5 with probability\frac{j}{j+k}, so the expected number of "HILO"s increases by\frac{j}{j+k}.
在计算 HI,如果我们现在选的数 LO那么HILO的出现次数就会加一。因为选一个小于 HILO的期望出现次数会增加
So, we have the recurrence
dp[1][j][k] = \frac{\sum_{j_2 < j} dp[0][j_2][k] + \sum_{k_2 < k} dp[1][j][k_2]}{j+k} + \frac{j}{j+k}.
这样,我们得到转移方程
Now, we can compute every value of
dp[b][j][k] by iterating over allj_2 < j, k_2 < k and using the above recurrences. Since there areN^2 dp states and we sum overN smaller states, this leads to a time complexity of\mathcal{O}(N^3), which is enough for the first two subtasks.
至此,我们可以通过遍历一遍
To speed this up, note that the bottleneck of the runtime comes from computing the terms like
\sum_{j_2 < j} dp[0][j_2][k]. Now, suppose we are computing the valuedp[0][j][k] and want to find the value\sum_{j_2 < j} dp[0][j_2][k] without using a loop. To do this, note that we have already computed the value ofdp[0][j-1][k], which required the value of\sum_{j_2 < j-1} dp[0][j_2][k]. Since we have already computed\sum_{j_2 < j-1} dp[0][j_2][k], we can use the fact that\sum_{j_2 < j} dp[0][j_2][k] = dp[0][j-1][k]+\sum_{j_2 < j-1} dp[0][j_2][k], which takes\mathcal O(1) time instead of\mathcal O(N) time to compute.
考虑优化转移,注意到算法的瓶颈在于计算像
Since we can now compute the
N^2 terms of the DP in\mathcal O(1) time each, our overall time complexity is now\mathcal{O}(N^2).
这样我们就可以以
翻译到此结束,以下提供优质 500B 代码。
// Nothing is Given, Everything is Earned.
#include<bits/stdc++.h>
using namespace std;
using L=long long;
const int N=5.1e3,P=1e9+7;
int dp[2][N][N],sum1[N],sum0[N],inv[N];
int main()
{
int n,x,y; cin>>n>>x; y=n-x;
inv[1]=1;
for(int i=2;i<=n;i++) inv[i]=1ll*(P-P/i)*inv[P%i]%P;
for(int j=0;j<=x;j++)
for(int k=0;k<=y;k++)
{
dp[0][j][k]=1ll*(sum1[j]+sum0[k])*inv[j+k]%P;
dp[1][j][k]=1ll*(sum1[j]+sum0[k]+j)*inv[j+k]%P;
(sum1[j]+=dp[1][j][k])%=P;
(sum0[k]+=dp[0][j][k])%=P;
}
L ans=dp[0][x][y];
for(L i=1;i<=n;i++) ans=1ll*ans*i%P;
cout<<ans<<endl;
return 0;
}