Welcome to Konjac Binaries'|

Binaries

园龄:3年5个月粉丝:11关注:1

【题解】CF1628D2 Game on Sum (Hard Version)

题目传送门

思路

这是一道DP题。

所以我们来设状态,我们让 dpi,j 表示在第 i 次操作后, Bob 选择“加”了 j 次,那么显然最后的答案是 dpn,m

再来看转移:

dpi,j 的 i 一定由 i-1 转移而来,而 j 则取决于 Bob 加不加,所以可以贡献给它的状态是 dpi1,jdpi1,j1

反过来说, dpi,j 可以给 dpi+1,jdpi+1,j+1 作出贡献。

先考虑转移。

显然,Alice 作出决策后, Bob 会在 dpi1,jtdpi1,j1+t 中选择最小的一个。

所以,Alice显然要让它们相等,否则Alice就会亏一波。

也就是,她会让 这个状态的 x =dpi1,j   + dpi1,j12,因为只有这样才可以保证 dpi1,jtdpi1,j1+t 中没有最小值,Alice才不会亏。

边界为 dpi,0=0(一次都不加,Alice当然全选 0 )和 dpi,i=ik (全加,Alice当然要拉满)。

看起来,接下来是一个 Θ(nm) 的 dp。

不过,我们发现,它的转移很像一个杨辉三角!

所以,我们考虑 dpi,idpn,m 的贡献。(因为在填充之前只有它们可以对答案造成贡献)

dpi,j 只能给 dpi+1,jdpi+1,j+1 作出贡献。

所以,它需要连续将 i 进行一些 +1 ,并选择一些来把 j 也来加够。

然而,如果直接分析, dpi,i 会给 dpi+1,i+1 贡献,然而这里已经填好了,所以会挂。

注意到 dpi,j 不能贡献给 dpi,j+1 ,我们考虑从 dpi+1,i 开始计算答案。

这时,向 n 需要加 ni1 ,向 m 需要加 mi ,而这 mi 一共有 (ni1mi) 种方案,需要乘上。

而在这个过程中,它显然会被不断除2,一共会除 ni 次,因为我们直接从 dpi+1,i 开始转移就意味着已经进行了一次操作。

显然如果 m 超过规定范围 Bob 就亏了,所以考虑用 m 来限制枚举变量。

最后的答案,就是 i=1mik  (ni1mi)2ni

当然,如果 n=m ,前面也说过, dpi,i 不应当再给它作贡献,此时的答案是 km ,应当特判。

预处理 2i 的逆元,复杂度 Θ(n)

代码

//吾日八省吾身:
//输入多而不快读乎?
//题目标注而不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 中国大陆许可协议进行许可。

posted @   Binaries  阅读(55)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.