"蔚来杯"2022牛客暑期多校训练营7 J: Melborp Elcissalc
原题:https://ac.nowcoder.com/acm/contest/33192/J
题目大意
题解
首先纯纯暴力肯定不行,必会超时
先求前缀和,以sum表示,对于每个sum取模k,不影响结果。即
s
u
m
i
=
(
s
u
m
i
−
1
+
a
i
)
%
k
sum_i=(sum_i-_1+a_i)\%k
sumi=(sumi−1+ai)%k
若区间
[
i
,
j
]
[i,j]
[i,j]中
s
u
m
i
=
s
u
m
j
sum_i=sum_j
sumi=sumj ,则该区间的和为
k
k
k的倍数,不难证明
接下来,设
n
u
m
i
num_i
numi 表示
s
u
m
x
=
i
sum_x=i
sumx=i 的数量,则方案数为
然后就可以用dp求方案数了
设
d
p
i
,
j
,
k
dp_i,_j,_k
dpi,j,k ,表示已用了
[
0
,
i
]
[0,i]
[0,i]区间内的数,填了
i
i
i个位置,合法数为
k
k
k的方案数,则转移式为
其中
s
=
n
u
m
i
s=num_i
s=numi
所以最终结果为
a
n
s
=
d
p
k
−
1
,
n
,
t
ans=dp_k-_1,_n,_t
ans=dpk−1,n,t
进行四维暴力枚举,时间复杂度
O
(
6
4
5
)
\large O(64^5)
O(645) 大约等于
1
0
9
10^9
109,勉强能过
参考代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=110;
const int M=(1<<12)+10;
const int mod=998244353;
ll c[N][N];
ll dp[N][N][M];
ll n,k,t;
void init(){
for(int i=0;i<=100;i++) {
for (int j=0;j<=i;j++) {
if(!j)c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
for(int j=0;j<=n;j++)
dp[0][j][c[j+1][2]]=1;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>k>>t;
init();
for (int i=1;i<k;i++)
for (int j=0;j<=n;j++)
for (int u=0;u<=t;u++)
for (int l=0;l+j<=n;l++)
(dp[i][j+l][u+c[l][2]]+=dp[i-1][j][u]*c[j+l][l])%=mod;
cout<<dp[k-1][n][t];
return 0;
}
另:
真就勉勉强强,有巨佬写了3毫秒代码,真的强,可以研究一下
链接:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=53258713
(by 二巨佬带我一废物 )