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的最小代价
*/
}

浙公网安备 33010602011771号