引
在某些思想上跟
象棋
象棋
象棋 那道很相似
虽然可能只有我这样认为
解法
倒序进行加数的过程,那么当你倒序加入了一个数后。若为
1
1
1,则
S
+
1
S+1
S+1; 若为
−
1
-1
−1,则为
max
{
0
,
S
−
1
}
\max\{0,S-1\}
max{0,S−1}
那么设计
D
P
DP
DP状态后,就发现
f
i
,
j
f_{i,j}
fi,j 由
f
i
+
1
,
j
+
1
f_{i+1,j+1}
fi+1,j+1 和
f
i
+
1
,
max
{
0
,
j
−
1
}
f_{i+1,\max\{0,j-1\}}
fi+1,max{0,j−1}转移而来
但是对于每一个关于
k
k
k 的询问,我们都会单独算一轮;
可我们可以优化,写出具体的转移式:
f
i
,
j
=
p
i
+
1
f
i
+
1
,
j
+
1
+
(
1
−
p
i
+
1
)
f
i
+
1
,
max
{
0
,
j
−
1
}
f_{i,j} =p_{i+1} f_{i+1,j+1}+(1-p_{i+1})f_{i+1,\max\{0,j-1\}}
fi,j=pi+1fi+1,j+1+(1−pi+1)fi+1,max{0,j−1}
在写出
f
i
+
1
,
j
+
1
.
.
.
.
.
.
f_{i+1,j+1}......
fi+1,j+1......的转移式,就会发现我们可以求出每个
f
i
,
j
f_{i,j}
fi,j 系数,当询问 某个
k
k
k 时,就相当于令
f
k
,
0
=
1
f_{k,0}=1
fk,0=1 ,再带入
f
k
,
0
f_{k,0}
fk,0 的系数即可,我们用动态规划求出系数即可,转移于
f
f
f的转移类似
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
const int N=5e3+7;
const ll mod=1e9+7;
int n;
ll f[N][N];
struct st { ll p,q; } p[N];
ll qpow(ll ba,ll pow) {
ll res=1; while(pow) {
if(pow&1) res=res*ba%mod;
ba=ba*ba%mod,pow>>=1;
} return res;
}
int main() {
int T; scanf("%d",&T); while(T--) {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
ll x,y,z;
scanf("%lld%lld",&x,&y),z=(y-x),y=qpow(y,mod-2);
p[i].p=x*y%mod,p[i].q=z*y%mod;
}
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) f[i][j]=0;
for(int i=0;i<=n;i++) scanf("%lld",&f[0][i]);
for(int i=0;i<n;i++) {
for(int j=0;j<=n-i;j++) {
if(!j) f[i+1][0]=(f[i+1][0]+f[i][j]*p[i+1].q%mod)%mod,f[i+1][1]=(f[i+1][1]+f[i][j]*p[i+1].q%mod)%mod;
else f[i+1][j-1]=(f[i+1][j-1]+f[i][j]*p[i+1].p%mod)%mod,f[i+1][j+1]=(f[i+1][j+1]+f[i][j]*p[i+1].q%mod)%mod;
}
printf("%lld ",f[i+1][0]);
}
puts("") ;
}
}