题解:CF1628D1 Game on Sum (Easy Version)
CF1628D1 题解
题面
题意
初始时,有一个数 \(ans=0\)。
有两个人,第一个人要在 \([0,k]\) 选出一个实数 \(t\)。
第二个人可以选择让 \(ans\) 加 \(t\) 或减 \(t\)。
总共有 \(n\) 轮,第二个人至少要操作 \(m\) 次,且两个人都会使用最优策略。
思路
容易发现,\(k\) 在题目中没啥大用,于是我们就假设 \(k=1\),这时候设最后的 \(ans\) 就为 \(dp[n][m]\)。
开始考虑 \(dp\) 的转移方程,可以容易得到。
\(\begin{aligned} dp[i][j]=\max_{t=0/1}\{\min(dp[i-1]j-1]+t,dp[i-1][j]-t)\} \end{aligned}\)。
里面的是第二个人是否选择操作,外面的是第一个人要的最优的操作。
于是,由于 \(t\) 只可能为 \(0\) 或 \(1\),所以就可以进行分类讨论。
- 若 \(dp[i-1][j]-dp[i-1][j-1]\leqslant 2\),则 \(dp[i][j]=\frac{dp[i-1][j-1]+dp[i-1][j]}{2}\)。
- 若 \(dp[i-1][j]-dp[i-1][j-1]>2\),则 \(dp[i][j]=dp[i-1][j-1]+1\)。
接下来我们发现对于一个 \(dp[n][m]\),有 \(dp[n][m+1]-dp[n][m]\leqslant 2\),证明如下。
证明:\(\begin{aligned} dp[n][m+1]-dp[n][m]&=\frac{dp[n-1][m]+d[n-1][m+1]}{2}-\frac{dp[n-1][m-1]+dp[n-1][m]}{2} \\&=\frac{dp[n-1][m+1]-dp[n-1][m-1]}{2}\\&=\frac{dp[n-1][m+1]-dp[n-1][m]}{2}+\frac{dp[n-1][m]-dp[n-1][m-1]}{2}\\&\leqslant\frac{2}{2}+\frac{2}{2}\\&=2 \end{aligned}\)
即 \(dp[n][m+1]-dp[n][m]\leqslant 2\)。
所以,\(dp[i][j]\) 只能为 \(\frac{dp[i-1][j-1]+dp[i-1][j]}{2}\)。
观察到,除去分数线,就是一个杨辉三角,但是,显然,这样会 TLE(困难版),所以考虑线性统计 \(ans\)。
可以考虑 \(dp[i][i]\) 对 \(dp[n][m]\) 的影响,除去分数线,会发现其实就是从 \((i,i)\) 开始只能向下或向右下前进到 \((n,m)\) 的方案数,但是由于 \(dp[i+1][i+1]\) 是边界值,所以必能经过 \((i+1,i+1)\),那么就相当于从 \((i,i+1)\) 出发到 \((n,m)\) 的方案数,于是,就为 \(C^{m-i}_{n-i-1}\)。
当然,这里就有人问了,为什么呢?
首先,这是一个杨辉三角形(除去分数线)没错吧?于是通过数学归纳法可以证明杨辉三角形第 \(n\) 行的第 \(m\) 个为 \(C^{m}_{n}(m\geqslant 2)\)。
证明:已知,杨辉三角的第一行为 \(1\),第二行为 \(1,1\),两行均满足猜想。
接下来,对于第 \(n\) 行(\(n>2\)),第 \(m\) 个数(\(m\geqslant2\))为 \(\begin{aligned}C^{m-1}_{n-1}+C^{m}_{n-1}&=\frac{(n-1)\times(n-2)\times\cdots\times(n-m+1)}{(m-1)!}+\frac{(n-1)\times(n-2)\times\cdots\times(n-m)}{m!}\\&=\frac{(n-1)\times(n-2)\times\cdots\times(n-r+r)}{m!}\\&=\frac{(n-1)\times(n-2)\times\cdots\times(n-m)}{m!}\\&=C^{m}_{n}\end{aligned}\)
证毕。
接下来,再加上分数线,就可以得到 \(\begin{aligned}dp[n][m]=\sum^{m}_{i=1}\frac{i\times C^{m-i}_{n-i-1}}{2^{n-i}}\end{aligned}\)。
于是就有 \(\begin{aligned}ans=k\times\sum^{m}_{i=1}\frac{i\times C^{m-i}_{n-i-1}}{2^{n-i}}\end{aligned}\)。
预处理即可。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int INV=5e8+4,mod=1e9+7,MN=1e6+1;
//INV是2在模mod意义下的乘法逆元,在此意义下*INV就等价于/2
long long fac[MN],inv[MN],T,n,m,k,ans;
//fac[i]表示i!的值,inv[i]表示fac[i]在模1e9+7意义下的乘法逆元
long long ksm(long long a, long long b) {
long long res=1;
while(b) {
if(b&1) res=res*a%mod;
a=a*a%mod;
b=b>>1;
}
return res;
}
long long C(long long m, long long n) {
if(n==m||n==0) return 1;
return fac[m]*inv[n]%mod*inv[m-n]%mod;
}
int main(){
fac[0]=1;
for(long long i=1; i<MN; i++){
fac[i]=fac[i-1]*i%mod;
inv[i]=ksm(fac[i],mod-2);
}
scanf("%lld %lld %lld",&n,&m,&k);
if(n==m) printf("%lld\n",n*k%mod);
else{
for(long long i=1; i<=m; i++) ans=(ans+ksm(INV,n-i)*i%mod*C(n-i-1,m-i)%mod)%mod;
printf("%lld\n",ans*k%mod);
}
return 0;
}