cf Educational Codeforces Round 141 D. Different Arrays

D. Different Arrays
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

You are given an array a consisting of n integers.

You have to perform the sequence of n−2 operations on this array:

during the first operation, you either add a 2 a_2 a2 to a 1 a_1 a1 and subtract a 2 a_2 a2 from a 3 a_3 a3, or add a 2 a_2 a2 to a 3 a_3 a3 and subtract a 2 a_2 a2 from a 1 a_1 a1;
during the second operation, you either add a 3 a_3 a3 to a 2 a_2 a2 and subtract a 3 a_3 a3 from a 4 a_4 a4, or add a 3 a_3 a3 to a 4 a_4 a4 and subtract a 3 a_3 a3 from a 2 a_2 a2;

during the last operation, you either add a n − 1 a_{n−1} an1 to a n − 2 a_{n−2} an2 and subtract a n − 1 a_{n−1} an1 from a n a_n an, or add a n − 1 a_{n−1} an1 to an and subtract a n − 1 a_{n−1} an1 from a n − 2 a_{n−2} an2.

So, during the i-th operation, you add the value of a i + 1 a_{i+1} ai+1 to one of its neighbors, and subtract it from the other neighbor.

For example, if you have the array [1,2,3,4,5], one of the possible sequences of operations is: subtract 2 from a 3 a_3 a3 and add it to a 1 a_1 a1, so the array becomes [3,2,1,4,5];
subtract 1 from a 2 a_2 a2 and add it to a 4 a_4 a4, so the array becomes [3,1,1,5,5];
subtract 5 from a 3 a_3 a3 and add it to a 5 a_5 a5, so the array becomes [3,1,−4,5,10];
So, the resulting array is [3,1,−4,5,10].
An array is reachable if it can be obtained by performing the aforementioned sequence of operations on a. You have to calculate the number of reachable arrays, and print it modulo 998244353.

Input
The first line contains one integer n (3≤n≤300).

The second line contains n integers a1,a2,…,an (0≤ai≤300).
Output

Print one integer — the number of reachable arrays. Since the answer can be very large, print its remainder modulo 998244353.

Examples
Input
4
1 1 1 1

Output
3

Input
5
1 2 3 5 0

Output
7

中文:
给你n个数,用 a i a_i ai表示,执行n-2次操作。
第一次操作有两种选择, a 1 + = a 2 , a 3 − = a 2 a_1 += a_2,a_3 -= a_2 a1+=a2,a3=a2或者 a 1 − = a 2 , a 3 + = a 2 a_1 -= a_2,a_3 += a_2 a1=a2,a3+=a2
第二次操作同样, a 2 + = a 3 , a 4 − = a 3 a_2 += a_3,a_4 -= a_3 a2+=a3,a4=a3或者 a 2 − = a 3 , a 4 + = a 3 a_2 -= a_3,a_4 += a_3 a2=a3,a4+=a3
第n-2此操作为, a n − 2 + = a n − 1 , a n − = a n − 1 a_{n-2} += a_{n-1},a_n -= a_{n-1} an2+=an1,an=an1或者 a n − 2 − = a n − 1 , a n + = a n − 1 a_{n-2} -= a_{n-1},a_n += a_{n-1} an2=an1,an+=an1
最后问你这n个数组成的序列有多少中变化。结果mod上一个大质数。

代码:

#include 
using namespace std;
 
typedef long long ll;
const int maxn = 300 + 5;
const int mod = 998244353;
const int N = maxn * maxn;
int a[maxn];
int dp[maxn][2 * N + 1];
int n;
 
int main() {
    ios::sync_with_stdio(false);
    while (cin >> n) {
        memset(dp, 0, sizeof(dp));
        memset(a, 0, sizeof(a));
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        dp[2][a[2] + N] = 1;
        for (int i = 3; i <= n; i++) {
            for (int j = -N; j <= N; j++) {
                dp[i][a[i] + j + N] = (dp[i][a[i] + j + N] + dp[i - 1][j + N]) % mod;
                if (j) {
                    dp[i][a[i] - j + N] = (dp[i][a[i] - j + N] + dp[i - 1][j + N]) % mod;
                }
            }
        }
        int ans = 0;
        for (int i = 0; i <= N * 2; i++) {
            ans = (ans + dp[n][i]) % mod;
        }
        cout << ans << endl;
    }
    return 0;
}

解答:

这里参考官方题解中的解释,官方题解写的非常详细。
第i次操作, a i + = a i + 1 , a i + 2 − = a i + 1 a_i += a_{i+1},a_{i+2} -= a_{i+1} ai+=ai+1,ai+2=ai+1或者 a i − = a i + 1 , a i + 2 + = a i + 1 a_i -= a_{i+1},a_{i+2} += a_{i+1} ai=ai+1,ai+2+=ai+1
首先注意到数据 a i a_i ai的范围是[0, 300],这明显是可以通过记录数据值来作为状态。
此外要注意到,第i此操作后,[1,i-1]个数是不变的,而且不影响i+3及其之后的数。
这里使用dp来考虑,设置状态 d p [ i ] [ x ] [ y ] dp[i][x][y] dp[i][x][y],表示第i次操作时 a i + 1 a_{i+1} ai+1为x, a i + 2 a_{i+2} ai+2为y时有多少种前缀的数量,经过第i次操作后, a i + 3 a_{i+3} ai+3及其之后的序列值就是原始的序列值,没有变化, a i a_{i} ai以及之前的值不会再发生变化。所以仅关注 a i + 1 a_{i+1} ai+1 a i + 2 a_{i+2} ai+2即可。

状态转移方程比较好想,执行第i+1次操作时,会对 a i + 1 , a i + 3 a_{i+1},a_{i+3} ai+1,ai+3产生影响。
如果第i+1次操作是 a i + 1 + = a i + 2 , a i + 3 − = a i + 2 a_{i+1} += a_{i+2},a_{i+3} -= a_{i+2} ai+1+=ai+2,ai+3=ai+2,那么状态转移为:
d p [ i + 1 ] [ y ] [ a i + 3 − y ] dp[i+1][y][a_{i+3} - y] dp[i+1][y][ai+3y] 这里很明显,第i次操作时的 a i + 2 a_{i+2} ai+2对应的值,变成了相对于第i+1次操的" a i + 1 a_{i+1} ai+1",即y;同理相对于第i+1次操作的" a i + 2 a_{i+2} ai+2“ ,及 a i + 3 a_{i+3} ai+3这时对应的操作就是减去y。

如果第i+1次操作是 a i + 1 − = a i + 2 , a i + 3 + = a i + 2 a_{i+1} -= a_{i+2},a_{i+3} += a_{i+2} ai+1=ai+2,ai+3+=ai+2,那么状态转移为:
d p [ i + 1 ] [ y ] [ a i + 3 + y ] dp[i+1][y][a_{i+3} + y] dp[i+1][y][ai+3+y]

注意,如果y等于0的时候,上面的两种操作对应的状态相同,属于重复运算了,需要判断。

以上状态会导致超时,注意到 a i + 1 a_{i+1} ai+1维度不会对状态转移产生影响,可以直接去掉。

考虑第i+1次操作,对 a i + 2 a_{i+2} ai+2有影响,状态转移为:
d p [ i + 1 ] [ a i + 1 + j ] + = d p [ i ] [ j ] dp[i+1][a_{i+1}+j] += dp[i][j] dp[i+1][ai+1+j]+=dp[i][j] 这里注意 d p [ i ] [ j ] dp[i][j] dp[i][j]中的j即为 a i + 2 a_{i+2} ai+2的可能范围
同理
d p [ i + 1 ] [ a i + 1 − j ] + = d p [ i ] [ j ] dp[i+1][a_{i+1}-j] += dp[i][j] dp[i+1][ai+1j]+=dp[i][j]

你可能感兴趣的:(动态规划,根本不会/就差一点/记得再看,算法,动态规划,图论)