At419 E - Subarray Sum Divisibility

E.Subarray Sum Divisibility


原题链接

题意简述

给你一个长度为 \(N\) 的整数序列 \(A = (A_1, A_2, \ldots, A_N)\)
您的目标是重复执行以下操作,使 \(A\) 的每个长度为 \(L\) 的连续子数组的和都是 \(M\) 的倍数。
选择 \(i\) 这样的整数 \(1 \leq i \leq N\) ,并将 \(A_i\) 的值增加 \(1\)
求在达到目标之前可能进行的最小运算次数。

解题思路

观察数据范围,发现很小,考虑数论做法或者dp转移。
观察最终状态,注意到:
1.\(\sum_{i=1}^{i+L-1} {A_i} = 0(mod M)\)
2.\(A_i \equiv A_{i+L}(mod M)\)
不难得到以下做法:
1.根据下标进行分组,依据数组下标 mod L 的值进行分组,代价累加为组内元素和。
2.定义dp数组,\(dp_{i,j}\)表示 前 i 组 的和为 j (mod m)的最小代价,进行背包dp即可
最后的代价就是在前 L 组 在 mod m 和为 0 的最小代价。

AC code

void solve(){
    int n,m,L;
    cin>>n>>m>>L;
    vector<int>a(n+1);
    vector< vector<ll> >b(501,vector<ll>(501));
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++) b[(i-1)%L+1][j]+=(j-a[i]%m+m)%m;
    }//b_{i,j},使得第 i 组 mod m意义下==j的代价
    vector< vector<ll> >dp(L+1,vector<ll>(m+1,INT_MAX));
    dp[0][0]=0;
    for(int i=1;i<=L;i++){
        for(int j=0;j<=m;j++){
            for(int k=0;k<=m;k++){
                if(dp[i-1][k]==INT_MAX) continue;
                dp[i][j]=min(dp[i][j],dp[i-1][k]+b[i][(j-k+m)%m]);
            }
        }
    }
    cout<<dp[L][0]<<endl;
    /*
    dp[i][j]=dp[i-1][(j-a[i])%m]
    前i组之和为x的最小代价
    */
}
posted @ 2025-08-22 19:26  usedchang  阅读(15)  评论(0)    收藏  举报