遇到简单 div.2,结果 D 写了一个巨大复杂的做法,调了 114 年没过。。。D1 还 fst 了。。。
为啥我会觉得优先队列 pop 清空内存而 vector swap 空指针不清空内存啊。。。
039 AGC052C Nondivisible Prefix Sums
首先考虑如何判定。(一个显然的条件是全局和不为 \(P\) 的倍数)
由于前缀和为 \(0\) 的限制是很松的,我们只要还有两个数就能避免不合法。于是考虑一种贪心策略:能填出现最多的数字就填它,否则填次大的。
不妨令出现最多的数字为 \(1\),否则我们可以将所有数乘上其逆元。那么我们一定是不断填 \(1\) 直到 \(P-1\),于是有:
\[tot_1\leqslant \sum_{i=1}^n[a_i\ne 1](P-a_i)+P-1
\]
右边很大,而左边很小,不妨容斥计算不合法的方案数。
令 \(f_{i,j}\) 表示长度为 \(i\) 的序列,右式值为 \(j\) 的方案数,可以发现 dp 状态也能表示是否合法:
\[f_{i,j}=\sum_{k=1}^{\min(p-2,j)}f_{i-1,j-k}
\]
前缀和优化即可,最后用组合数随便算算,复杂度 \(O(n^2)\)。
#include<stdio.h>
const int maxn=5005,mod=998244353;
int n,P,ans;
int C[maxn][maxn],f[maxn][maxn],sum[maxn],g[maxn];
int main(){
scanf("%d%d",&n,&P);
for(int i=0;i<=5000;i++){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
g[0]=0;
for(int i=1,mul=1;i<=n;i++,mul=1ll*mul*(P-1)%mod)
g[i]=(1ll*(P-2)*g[i-1]+1ll*(P-1)*(mul-g[i-1]+mod))%mod;
f[0][0]=1;
for(int i=1;i<=n;i++){
sum[0]=f[i-1][0];
for(int j=1;j<=n;j++)
sum[j]=(sum[j-1]+f[i-1][j])%mod;
for(int j=1;j<=n;j++)
f[i][j]=(sum[j-1]-(j-(P-2)>0? sum[j-(P-2)-1]:0)+mod)%mod;
}
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
if((n-i)%P-j%P!=0&&n-i>j+(P-1))
ans=(ans+1ll*f[i][j]*C[n][i])%mod;
printf("%d\n",(g[n]-1ll*(P-1)*ans%mod+mod)%mod);
return 0;
}
不如接受自己的颓怪事实。