【题解】CF1628D2 Game on Sum (Hard Version)
题目传送门
思路
这是一道DP题。
所以我们来设状态,我们让 表示在第 i 次操作后, Bob 选择“加”了 j 次,那么显然最后的答案是
再来看转移:
的 i 一定由 i-1 转移而来,而 j 则取决于 Bob 加不加,所以可以贡献给它的状态是 和 。
反过来说, 可以给 和 作出贡献。
先考虑转移。
显然,Alice 作出决策后, Bob 会在 和 中选择最小的一个。
所以,Alice显然要让它们相等,否则Alice就会亏一波。
也就是,她会让 这个状态的 x ,因为只有这样才可以保证 与 中没有最小值,Alice才不会亏。
边界为 (一次都不加,Alice当然全选 0 )和 (全加,Alice当然要拉满)。
看起来,接下来是一个 的 dp。
不过,我们发现,它的转移很像一个杨辉三角!
所以,我们考虑 对 的贡献。(因为在填充之前只有它们可以对答案造成贡献)
而 只能给 和 作出贡献。
所以,它需要连续将 i 进行一些 +1 ,并选择一些来把 j 也来加够。
然而,如果直接分析, 会给 贡献,然而这里已经填好了,所以会挂。
注意到 不能贡献给 ,我们考虑从 开始计算答案。
这时,向 n 需要加 ,向 m 需要加 ,而这 一共有 种方案,需要乘上。
而在这个过程中,它显然会被不断除2,一共会除 次,因为我们直接从 开始转移就意味着已经进行了一次操作。
显然如果 m 超过规定范围 Bob 就亏了,所以考虑用 m 来限制枚举变量。
最后的答案,就是 。
当然,如果 ,前面也说过, 不应当再给它作贡献,此时的答案是 ,应当特判。
预处理 的逆元,复杂度 。
代码
//吾日八省吾身:
//输入多而不快读乎?
//题目标注而不freopen乎?
//乘除并列先乘后除乎?
//不手撕样例直接写代码乎?
//不仔细读题直接关页面乎?
//1e9而不开long long乎?
//Ctrl+V而不改名称乎?(papaw->papan IMPLIES tg1=->2=)
//相信评测神机乎?
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime>
#include<sstream>
#include<list>
#include<bitset>
using namespace std;
typedef long long ll;
const ll MO(1000000007);
const ll MAXN(1000123);
ll fac[MAXN],inv[MAXN];
ll tpow[MAXN];
ll T,n,m,k,ans;
void R(ll &x){
x=0;ll f=1;char c='c';
while(c>'9'||c<'0'){f=f*(c=='-'?-1:1);c=getchar();}
while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
x=x*f;
return;
}
ll fpow(ll x,ll y){
ll res=1;
while(y){if(y&1) res=(res*x)%MO;x=(x*x)%MO;y>>=1;}
return res%MO;
}
void getfi(){
const ll MAXA=1000100;
fac[0]=inv[0]=tpow[0]=1;
for(int i=1;i<=MAXA;++i) fac[i]=(fac[i-1]*i)%MO,tpow[i]=(tpow[i-1]<<1)%MO;
inv[MAXA]=fpow(fac[MAXA],MO-2);tpow[MAXA]=fpow(tpow[MAXA],MO-2);
for(int i=MAXA-1;i>=1;--i) inv[i]=(inv[i+1]*(i+1))%MO,tpow[i]=(tpow[i+1]<<1)%MO;
return;
}
ll C(ll n,ll m){return (fac[n]*inv[m]%MO*inv[n-m]%MO);}
int main(){
getfi();
R(T);
while(T--){
R(n);R(m);R(k);ans=0;
if(n==m){printf("%lld\n",n*k%MO);continue;}
for(int i=1;i<=m;++i) ans=(ans+i*k%MO*C(n-i-1,m-i)%MO*tpow[n-i]%MO)%MO;
printf("%lld\n",ans);
}
return 0;
}
P.S.
温馨提示:可以到 D1 版本水双倍经验(bushi)
本文作者:Binaries
本文链接:https://www.cnblogs.com/Konjac-Binaries/p/16123411.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步