Loading

[ABC207E] Mod i 题解

Mod i

题目大意#

给定一个序列 a,问将其划分成若干段,满足第 i 段的和是 i 的倍数的划分方案的个数。

思路分析#

考虑 DP,设 fi,j 表示将序列中前 i 个数划分成 j 段,且满足条件的划分方案的个数,容易得出状态转移方程:

fi,j=fk,j1(h=k+1iaimodj=0)

直接转移的复杂度是 O(n3) 的,无法接受,考虑优化。

sia 的前 i 项和,那么约束条件等价于 (sisk)modj=0,当条件成立时有 sisk(modj)

可以设 gi,j=fk,i(skmod(i+1)=j),那么容易发现

gj1,simodj=fk,j1(skmodj=simodj)=fi,j

这样转移就优化到了 O(n2),这是因为 g 可以在转移时累加,即

gj,simod(j+1)=fk,j(skmod(j+1)=simod(j+1))

其中包含 fi,j

代码#

#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;
const int N=3200,mod=1000000007;
#define int long long

int f[N][N],g[N][N];
int sum[N],a[N];
int ans,n;

signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    f[0][0]=g[0][0]=1;//初始条件
    for(int i=1;i<=n;i++)
        for(int j=n;j>=1;j--){
            f[i][j]=g[j-1][sum[i]%j];
            g[j][sum[i]%(j+1)]=(g[j][sum[i]%(j+1)]+f[i][j])%mod;
        }
    for(int i=1;i<=n;i++) ans=(ans+f[n][i])%mod;//累加答案
    cout<<ans<<'\n';
    return 0;
}

作者:TKXZ133

出处:https://www.cnblogs.com/TKXZ133/p/17457546.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   TKXZ133  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示