A - Many Formulae
题目大意:
给你n个数字,进行 + 或 - 的操作,其中 - 操作不能连续进行两次或两次以上,求所有可能情况的和
思路:
dp[i][0] 表示以 +a[i] 结尾的和,cnt[i][1] 表示以 -a[i] 结尾和
cnt[i][0] 表示以 +a[i] 结尾的个数,cnt[i][1] 表示以 -a[i] 结尾的个数
由此可得
{
d
p
[
i
]
[
0
]
=
(
d
p
[
i
−
1
]
[
0
]
+
d
p
[
i
−
1
]
[
1
]
)
+
(
c
n
t
[
i
−
1
]
[
0
]
+
c
n
t
[
i
−
1
]
[
1
]
)
×
a
i
d
p
[
i
]
[
1
]
=
d
p
[
i
−
1
]
[
0
]
—
c
n
t
[
i
−
1
]
[
0
]
×
a
i
{
c
n
t
[
i
]
[
0
]
=
c
n
t
[
i
−
1
]
[
0
]
+
c
n
t
[
i
−
1
]
[
1
]
c
n
t
[
i
]
[
1
]
=
c
n
t
[
i
−
1
]
[
0
]
\begin{cases} dp[i][0]=(dp[i-1][0]+dp[i-1][1])+(cnt[i-1][0]+cnt[i-1][1])\times a_i\\ dp[i][1]=dp[i-1][0]—cnt[i-1][0]\times a_i\\ \end{cases} \\ \begin{cases} cnt[i][0]=cnt[i-1][0]+cnt[i-1][1]\\ cnt[i][1]=cnt[i-1][0]\\ \end{cases}
{dp[i][0]=(dp[i−1][0]+dp[i−1][1])+(cnt[i−1][0]+cnt[i−1][1])×aidp[i][1]=dp[i−1][0]—cnt[i−1][0]×ai{cnt[i][0]=cnt[i−1][0]+cnt[i−1][1]cnt[i][1]=cnt[i−1][0]
最后答案为dp[n][1] + dp[n][0]
注意减法的取模运算,有可能减出负数,此时进行取模后还是负数,所以要使用以下方法取模:
ll MOD (ll x) {
return (x % mod + mod) % mod;
}
AC代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7, N = 1e6 + 10;
ll dp[N][2], a[N], m[N], cnt[N][2];
ll MOD (ll x) {
return (x % mod + mod) % mod;
}
int main ()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++)
{
cin >> a[i];
a[i] %= mod;
}
if (n == 1)
{
cout << a[1] % mod << endl;
return 0;
}
dp[2][0] = MOD(a[1] + a[2]);
dp[2][1] = MOD(a[1] - a[2]);
cnt[2][0] = 1;
cnt[2][1] = 1;
for (int i = 3; i <= n; i ++)
{
dp[i][0] = ((dp[i - 1][0] % mod + dp[i - 1][1] % mod) + (cnt[i - 1][0] % mod + cnt[i - 1][1] % mod) * a[i] % mod) % mod;
cnt[i][0] = (cnt[i - 1][0] % mod + cnt[i - 1][1] % mod) % mod;
dp[i][1] = MOD(dp[i - 1][0] % mod - cnt[i - 1][0] * a[i] % mod);
cnt[i][1] = cnt[i - 1][0] % mod;
}
cout << (dp[n][0] + dp[n][1]) % mod << endl;
}