[海军国际项目办公室]猪国杀
猪国杀


题解
为什么总有**出题人喜欢用一些毒瘤题的题目名字来命名题目呀。
看到这种题一般很容易想到通过
d
p
dp
dp来进行转移吧。
我们先考虑一下如果我们要选牌的话怎么选才能让我们获得的牌尽量多,显然是从小的选起会让我们的牌的总数尽可能的大。
为了避免枚举牌的去重容斥操作,我们可以考虑确定我们选牌的顺序,就是选较小的牌,根据每一种选牌的方案确定我们整个牌的序列。
我们可以就将牌按照从小到大的顺序加入,构造我们所选择牌的序列。
我们定义
d
p
i
,
j
dp_{i,j}
dpi,j表示选择了
i
i
i张牌,总和为
j
j
j的方案数。
转移十分显然,如果我们已经选择加入到权值为
x
x
x的牌,枚举其加入的张数
k
k
k,
d
p
i
+
k
,
j
+
k
x
+
=
(
i
+
k
i
)
d
p
i
,
j
dp_{i+k,j+kx}+=\binom{i+k}{i}dp_{i,j}
dpi+k,j+kx+=(ii+k)dpi,j
当然,如果加上我们选择的卡,它的总和已经大于
m
m
m了,相当于它的选择卡的序列已经固定下来了,我们可以将这种情况加入答案。
但要注意,最后加入的卡可能会有多张,但我们只会从中选择部分,但还是得枚举选择了多少张。
我们记
t
=
⌊
m
−
j
x
⌋
t=\left\lfloor\frac{m-j}{x}\right\rfloor
t=⌊xm−j⌋,显然,我们最后选择的卡牌只会有
t
t
t张加入答案,那么计算
d
p
i
,
j
dp_{i,j}
dpi,j的贡献时我们可以枚举选择的卡牌张数,
A
n
s
+
=
∑
k
=
t
+
1
n
−
i
(
i
+
t
)
(
n
i
)
(
n
−
i
k
)
(
A
−
x
)
n
−
i
−
k
d
p
i
,
j
A
n
Ans+=\frac{\sum_{k=t+1}^{n-i}(i+t)\binom{n}{i}\binom{n-i}{k}(A-x)^{n-i-k}dp_{i,j}}{A^n}
Ans+=An∑k=t+1n−i(i+t)(in)(kn−i)(A−x)n−i−kdpi,j
显然,除了我们枚举的选择权值
x
x
x的位置,其它的位置权值都比
x
x
x大,所以有
(
A
−
x
)
(A-x)
(A−x)种选择。
所以我们对于
d
p
i
,
j
dp_{i,j}
dpi,j的转移是在
k
⩽
t
k\leqslant t
k⩽t时转移到
d
p
i
+
k
,
j
+
k
x
dp_{i+k,j+kx}
dpi+k,j+kx,当
k
>
t
k>t
k>t时贡献到答案。
这样的话时间复杂度是
O
(
n
2
m
A
)
O\left(n^2mA\right)
O(n2mA),考虑优化。
显然,可以发现,我们贡献到答案的部分
d
p
i
,
j
dp_{i,j}
dpi,j的系数
(
i
+
t
)
(
n
i
)
(
n
−
i
k
)
(
A
−
x
)
n
−
i
−
k
(i+t)\binom{n}{i}\binom{n-i}{k}(A-x)^{n-i-k}
(i+t)(in)(kn−i)(A−x)n−i−k其实可以被拆成两段来看,
(
i
+
t
)
(i+t)
(i+t),对于每个
j
j
j是独立的,可以在枚举到
j
j
j时
O
(
1
)
O\left(1\right)
O(1)算出。
(
n
i
)
(
n
−
i
k
)
(
A
−
x
)
n
−
i
−
k
\binom{n}{i}\binom{n-i}{k}(A-x)^{n-i-k}
(in)(kn−i)(A−x)n−i−k只与
i
i
i和
k
k
k相关。
我们完全可以对于第二部分在枚举
i
i
i时就将其前缀和算出,枚举
j
j
j时得到
t
t
t就可以差分出这段的和。
所以我们贡献到答案的部分实际上是可以
O
(
1
)
O\left(1\right)
O(1)求出的。
而贡献到
d
p
dp
dp的部分对于每个
d
p
i
,
j
dp_{i,j}
dpi,j是
O
(
t
)
O\left(t\right)
O(t)的。
由于
t
t
t是从
1
1
1枚举到
m
m
m的,显然是一个调和级数的形式,所以每个
d
p
i
,
j
dp_{i,j}
dpi,j会贡献
A
ln
m
−
j
A\ln m-j
Alnm−j次。
总时间复杂度 O ( n m A ln m ) O\left(nmA\ln m\right) O(nmAlnm),卡卡常就过了。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x<<'\n'
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int n1=50;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){putchar('\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,m,A,dp[2][105][MAXN],ans,fac[MAXN],inv[MAXN],f[MAXN],pw[105][MAXN],C[105][105],sum[1005];
void init(){
fac[0]=fac[1]=inv[0]=inv[1]=f[1]=1;
for(int i=2;i<=n;i++)
fac[i]=1ll*i*fac[i-1]%mo,
f[i]=1ll*(mo-mo/i)*f[mo%i]%mo,
inv[i]=1ll*f[i]*inv[i-1]%mo;
for(int i=0;i<=n;i++){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++)
C[i][j]=add(C[i-1][j-1],C[i-1][j],mo);
}
for(int i=0;i<=A;i++)pw[0][i]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=A;j++)
pw[i][j]=1ll*j*pw[i-1][j]%mo;
}
signed main(){
freopen("legend.in","r",stdin);
freopen("legend.out","w",stdout);
read(n);read(m);read(A);init();dp[0][0][0]=1;
for(int x=1;x<=A;x++){
int now=x&1,las=now^1;
for(int i=0;i<=n;i++)
for(int j=i;j<=m;j++)dp[now][i][j]=0;
for(int i=0;i<=n;i++){
sum[0]=0;
for(int k=1;k<=n-i;k++)
sum[k]=add(sum[k-1],1ll*C[n-i][k]*pw[n-i-k][A-x]%mo,mo);
for(int j=max(i,m-x+1);j<=m;j++)
Add(ans,1ll*i*C[n][i]%mo*dp[las][i][j]%mo*pw[n-i][A-x+1]%mo,mo);
for(int j=i;j<=m-x;j++)if(dp[las][i][j]){
int t=(m-j)/x;
for(int k=1,tp=x;k<=min(t,n-i);k++,tp+=x)
Add(dp[now][i+k][j+tp],1ll*C[i+k][k]*dp[las][i][j]%mo,mo);
if(n-i>t)Add(ans,1ll*add(sum[n-i],mo-sum[t],mo)*C[n][i]%mo*(i+t)%mo*dp[las][i][j]%mo,mo);
Add(dp[now][i][j],dp[las][i][j],mo);
}
}
}
for(int i=0;i<=m;i++)Add(ans,1ll*n*dp[A&1][n][i]%mo,mo);
printf("%d\n",1ll*ans*qkpow(qkpow(A,n,mo),mo-2,mo)%mo);
return 0;
}

浙公网安备 33010602011771号