E题:NAND repeatedly
标签:动态规划
题意:给定一个长度为
n
n
n的
01
01
01字符串
A
i
A_i
Ai,给定规则:
0
⊼
0
=
1
,
0
⊼
1
=
1
,
1
⊼
0
=
1
,
1
⊼
1
=
0
0⊼0=1,0⊼1=1,1⊼0=1,1⊼1=0
0⊼0=1,0⊼1=1,1⊼0=1,1⊼1=0。
求
∑
i
=
1
n
∑
j
=
i
n
f
(
i
,
j
)
\sum_{i=1}^n \sum_{j=i}^n f(i,j)
∑i=1n∑j=inf(i,j)(
1
<
=
i
<
=
j
<
=
n
1<=i<=j<=n
1<=i<=j<=n),
f
(
i
,
j
)
=
{
A
i
(
i
=
j
)
f
(
i
,
j
−
1
)
⊼
A
j
(
i
<
j
)
f(i,j)=\left\{\begin{matrix} A _ i&(i=j)\\ f(i,j-1)\barwedge A _ j\quad&(i\lt j) \end{matrix}\right.
f(i,j)={Aif(i,j−1)⊼Aj(i=j)(i<j)。
题解:显然我们可以通过
O
(
n
2
)
O(n^2)
O(n2)时间复杂度完成这道题要求,但是
n
<
=
1
0
6
n<=10^6
n<=106会超时。
d
p
[
i
]
[
0
/
1
]
dp[i][0/1]
dp[i][0/1]:前
i
i
i个数字累计
n
a
n
d
(
⊼
)
nand(⊼)
nand(⊼)为
0
/
1
0/1
0/1的方案数。分以下两种情况考虑:
- 当前数字是 0 0 0, d p [ i ] [ 1 ] dp[i][1] dp[i][1]累计是 1 1 1的情况可以从前面 i − 1 i-1 i−1累计是 0 0 0和 1 1 1的情况转移过来,因为当前数字是 0 0 0,不管和 0 0 0和 1 1 1 n a n d ( ⊼ ) nand(⊼) nand(⊼)都是 1 1 1; d p [ i ] [ 0 ] dp[i][0] dp[i][0]累计是 0 0 0的情况初始化成 1 1 1。
- 当前数字是 1 1 1, d p [ i ] [ 1 ] dp[i][1] dp[i][1]累计是 1 1 1的情况只能从前面 i − 1 i-1 i−1累计是 0 0 0的情况转移过来,并且计数增加 1 1 1(算上自己本身的),因为 1 ⊼ 1 = 0 1⊼1=0 1⊼1=0; d p [ i ] [ 0 ] dp[i][0] dp[i][0]累计是 0 0 0的情况从前面 i − 1 i-1 i−1累计是 1 1 1的情况转移过来。
最后把每个位置的
d
p
[
i
]
[
1
]
dp[i][1]
dp[i][1]累加一下即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
ll dp[N][2];
int main() {
ll n, ans = 0;
string s;
cin >> n >> s;
for (int i = 1; i <= n; i++) {
if (s[i-1] == '0') {
dp[i][1] = dp[i-1][0] + dp[i-1][1];
dp[i][0] = 1;
} else {
dp[i][1] = dp[i-1][0] + 1;
dp[i][0] = dp[i-1][1];
}
ans += dp[i][1];
}
cout << ans << endl;
return 0;
}