题解:P10740 [SEERC 2020] Divisible by 3
zxw12345678 · · 题解
显然意见的 DP 水题。
状态定义
设
转移过程
对于数组中的每个元素
-
先取模:
m = x \bmod 3 -
设处理前的前缀状态为
(u_{prev}, v_{prev}) ,处理后为(u_{now}, v_{now}) :u_{\text{now}} = (u_{\text{prev}} + [m = 1]) \bmod 3 v_{\text{now}} = (v_{\text{prev}} + [m = 2]) \bmod 3 -
统计所有能与当前前缀构成合法区间的前缀数量:
\Delta = dp[u_{\text{now}}][v_{\text{now}}] + dp[u_{\text{now}}][(v_{\text{now}} - 1 + 3) \bmod 3] + dp[(u_{\text{now}} - 1 + 3) \bmod 3][v_{\text{now}}] -
更新答案:
ans = ans + \Delta -
将当前前缀状态计入统计:
dp[u_{\text{now}}][v_{\text{now}}] = dp[u_{\text{now}}][v_{\text{now}}] + 1
算法复杂度
- 时间复杂度:
O(n) 。 - 空间复杂度:
O(1) 。
Code
:::success[代码]
似乎很少。
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
int n,cnt[3][3]={{0}},p1=0,p2=0,ans=0,x;
cin>>n;
cnt[0][0]=1;
for (int i=0;i<n;i++){
cin>>x;
if(x%3==1) p1=(p1+1)%3;
else if(x%3==2) p2=(p2+1)%3;
ans=ans+cnt[p1][p2]+cnt[p1][(p2-1+3)%3]+cnt[(p1-1+3)%3][p2];
cnt[p1][p2]++;
}
cout<<ans<<'\n';
return 0;
}
::: 完结散花!