J题: Melborp Elcissalc
链接:https://ac.nowcoder.com/acm/contest/33192/J
题目大意 :**
题解:
先举个栗子,1 3 2 4 3 ,若要求区间和可以先求前缀和 ,记为sum[i]=(sum[i-1]+
a
i
a_i
ai)%k;
应为只需考虑区间和是否为K的倍数,所以模K;
当sum[i]=sum[j]时 [i,j-1]即为一条目标子序列;所以一种sum可以得到的答案数为
C
s
u
m
的个数
2
C_{sum的个数}^2
Csum的个数2 记每种sum个数为num[i],那么最终符合要求的序列数为
∑
i
=
0
k
−
1
n
u
m
[
i
]
=
t
\sum\limits_{i=0}^{k-1}num[i]=t
i=0∑k−1num[i]=t.;
用
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k来表示已使用了[0,i]区间内的数,长度为j的序列,合法数为k的方案数;
转移方程为
d
p
i
,
j
,
k
=
dp_{i,j,k}=
dpi,j,k=
∑
s
=
0
j
d
p
i
−
1
,
j
−
s
,
k
−
C
s
2
∗
C
n
−
j
+
s
s
\sum\limits_{s=0}^{j}dp_{i-1,j-s,k-C_s^2}*C_{n-j+s}^s
s=0∑jdpi−1,j−s,k−Cs2∗Cn−j+ss
ans=dp[k-1][n][t];
(对于每个 C n m C_n^m Cnm可以先进行预处理)
***参考代码:***
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
const int mod= 998244353;
ll t,n,k,sum[1000],num[1000],c[100][100],dp[70][70][5000];
void init()
{
c[0][0]=1;
for(int i=1;i<=70;i++){
c[i][0]=1;
for(int j=1;j<=i;j++)
{
c[i][j]=c[i-1][j-1]+c[i-1][j];
if(c[i][j]>=mod)c[i][j]-=mod;}
}
}
int main(){
init();
cin>>n>>k>>t;
for(int j=0;j<=n;j++){
dp[0][j][c[j + 1][2]] = c[n][j];
}
for(int i=1;i<=k;i++)
{
for(int j=0;j<=n;j++)
{
for(int s=0;s<=t ;s++)
{
for(int y=0;y<=j&& s-c[y][2]>=0;y++)
{
dp[i][j][s]=dp[i][j][s]+ 1ll*dp[i-1][j-y][s- c[y][2] ] * c[n-j+y][y]%mod ;
if(dp[i][j][s]>=mod)
dp[i][j][s]-=mod;
}
}
}
}
cout<<dp[k-1][n][t]<<endl;
return 0;
}