Borrow[hdu-6829][期望dp][公式推导]

文章目录

题目

在这里插入图片描述
在这里插入图片描述

思路

首先说一说我考场思路
f ( x , y ) f(x,y) f(x,y) 最小值为 x x x,次小值为 y y y 到终点期望步数
然后有:
f ( x , y ) = 1 2 ( f ( t r a n s 1 ) + f ( t r a n s 2 ) ) + 1 f(x,y)=\frac{1}{2}(f(trans1)+f(trans2))+1 f(x,y)=21(f(trans1)+f(trans2))+1
然后高斯消元求解
可得 40 o p t 40opt 40opt
正解状态设置比较神仙,可能这类题目能比较套路地可以转化成组合数问题?
在这里插入图片描述
然后起始状态就是 f ( 0 , 0 ) = 0 f(0,0)=0 f(0,0)=0
这是转移:
在这里插入图片描述

然后可以将 ⑤ 中 f ( a + 1 , 2 ) f(a+1,2) f(a+1,2) 带入 ① 消元,以及 ③ 化简可得:
{ f ( a , 0 ) = f ( a − 1 , 1 ) + 2 f ( a , 1 ) = f ( a − 2 , 0 ) + 2 \begin{cases} f(a,0)=f(a-1,1)+2\\ f(a,1)=f(a-2,0)+2\\ \end{cases} {f(a,0)=f(a1,1)+2f(a,1)=f(a2,0)+2
然后发现它描述这样一个区域:
在这里插入图片描述
结合图像我们很轻易得到以下格点的函数值( y y y 轴同理)
{ f ( 3 k , 0 ) = 4 k f ( 3 k − 1 , 1 ) = 4 k − 2 \begin{cases} f(3k,0)=4k\\ f(3k-1,1)=4k-2\\ \end{cases} {f(3k,0)=4kf(3k1,1)=4k2
然后再看看非边界的转移:
在这里插入图片描述
发现它在走 马 马 字(两种方式)
然后可以计算每个边界点贡献
对于这个 + 1 +1 +1 可以分裂成两个 1 2 \frac{1}{2} 21 变成统计方案数最后除以 2 k 2^k 2k
值得注意的是 x x x 轴上的点第一次无法跳 ( + 1 , + 2 ) (+1,+2) (+1,+2)
对于两种走 马 马 字次数,可列出方程:
{ 2 x + y = d x 2 y + x = d y \begin{cases} 2x+y=d_x\\ 2y+x=d_y\\ \end{cases} {2x+y=dx2y+x=dy
发现 x , y x,y x,y 是固定值,只是顺序影响,组合数计算即可
注意 x x x 轴第一步
一次贡献: 1 2 k ( x + y + 1 / 0 + v a l ) \frac{1}{2^k}(x+y+1/0+val) 2k1(x+y+1/0+val)
y y y 轴翻折再计算即可

代码

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read(){
   bool f=0;int x=0;char c=getchar();
   while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
   while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
   return !f?x:-x;
}
#define mp make_pair
const int MAXN=2000000;
const int Mod=998244353;
const int inv2=499122177;
const int INF=0x3f3f3f3f;
int Add(int x,int y){x+=y;return x>=Mod?x-Mod:x;}
int Sub(int x,int y){x-=y;return x<0?x+Mod:x;}
int Mul(LL x,int y){x*=y;return x>=Mod?x%Mod:x;}
int Pow(int x,int y){
   int ret=1;
   while(y){
   	if(y&1) ret=Mul(ret,x);
   	x=Mul(x,x),y>>=1;
   }
   return ret;
}
int s;
int fac[MAXN+5],inv[MAXN+5],ipw2[MAXN+5];
int C(int n,int m){if(n<m||m<0)return 0;return Mul(fac[n],Mul(inv[m],inv[n-m]));}
int f(int x,int y){
   int ret=0;
   for(int k=1;3*k-1<=x;k++){
   	int dx=x-(3*k-1),dy=y-1;
   	int cntx=(2*dx-dy)/3,cnty=(2*dy-dx)/3;
   	if(cntx<0||cnty<0) continue;
   	ret=Add(ret,Mul(Mul(4ll*k-2+cntx+cnty,C(cntx+cnty,cntx)),ipw2[cntx+cnty]));
   }
   for(int k=1;3*k+1<=x;k++){
   	int dx=x-(3*k+1),dy=y-2;
   	int cntx=(2*dx-dy)/3,cnty=(2*dy-dx)/3;
   	if(cntx<0||cnty<0) continue;
   	ret=Add(ret,Mul(Mul(4ll*k+cntx+cnty+1,C(cntx+cnty,cntx)),ipw2[cntx+cnty+1]));
   }
   return ret;
}
int main(){
   //freopen("game.in","r",stdin);
   //freopen("game.out","w",stdout);
   fac[0]=1;
   ipw2[0]=1;
   for(int i=1;i<=MAXN;i++)
   	fac[i]=Mul(fac[i-1],i),ipw2[i]=Mul(ipw2[i-1],inv2);
   inv[MAXN]=Pow(fac[MAXN],Mod-2);
   for(int i=MAXN-1;i>=0;i--)
   	inv[i]=Mul(inv[i+1],i+1);
   int T=read();
   while(T--){
   	int X=read(),Y=read(),Z=read();
   	s=X+Y+Z;
   	if(s%3!=0){
   		puts("-1");
   		continue;
   	}
   	if(X>Y) swap(X,Y);
   	if(X>Z) swap(X,Z);
   	if(Y>Z) swap(Y,Z);
   	printf("%d\n",Add(f(Z-X,Z-Y),f(Z-Y,Z-X)));
   }
   return 0;
}
/*
3
114 514 191
244519070
*/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值