ATCoder_contest_abc220

D-FG operation

题目描述

我们有一个包含N个整数的序列,每个整数在0~9之间(包含0和9):A = (\(A_1\),......,\(A_n\)),被按照这个序列进行排列。我们将进行F操作和G操作,直到这个序列的长度为一。

  • 操作F:删除最左端的两个数(x1,x2),将(x1+x2)%10加到序列的最左端
  • 操作G:删除最左端的两个数(x1,x2),将(x1*x2)%10加到序列的最左端
    对于每一个k = 0,1,2,...,9
    在 2 的 N 次方减一种可能的方法中,有多少种操作方法,使得最后剩余的数字是 K。由于这个结果可能非常的大,请输出这个结果对998244353取模后的结果。
    数据规模
    2 <= N <= 1e5
    0 <= \(A_i\) <= 9
    原题链接

Input

3
2 7 6

Output

1
0
0
0
2
1
0
0
0
0

Input

5
0 1 2 3 4

Output

6
0
1
1
4
0
1
1
0
2
题解思路

对于一个长度为 N 的序列,可以先考虑最前面的两项,然后结果存到第二个位置上,第二个位置上有两种可能,一是分别进行F和G操作是产生了两个不同的数字,二是产生了两个相同的数字。这个时候,虽然第二个位置有很多种情况,但是对于给定的\(A_1\),\(A_2\),我们一定可以算出所有的可能,然后拿\(A_2\)位置上的所有可能与\(A_3\)进行F,G操作,\(A_3\)有可以算出来。然后要做的就是存了,我是开了一个arr[N][10]的数组,arr[i][9]表示把前 i-1 项消除之后第 i 位(即此时的第一位)剩余数字为 9,这样的方法有多少种。怎么更新呢?是个递推啊。假设arr[i-1][0~9]我们都知道,\(A_i\)是题目给出的,我们拿\(A_i\)对 0~9 分别进行F,G操作,比如 \(A_i\) = 3,当他对 0 进行F操作时,结果为3,我就让arr[i][3] += arr[i-1][0],当进行G操作时,结果也为3,我们就再arr[i][3] += arr[i-1][0],其他数字亦是如此。也就是说我们知道前一个的结果,可以推出后一个的结果,上代码。


AC代码
#include <iostream>
#define int long long
using namespace std;

const int N = 1e5 + 10;
const int mod = 998244353;

int arr[N][10],n;

signed main(){
    cin >> n;
    for(int i = 1; i <= n; i++){
        int a;
        cin >> a;
        arr[i][a]++; //初始化,记录第 i 个位置 Ai 的值(做标记)
    }
	
    for(int i = 2; i <= n; i++){
        int temp;
        for(int j = 0; j < 10; j++)
            if(arr[i][j] == 1) temp = j,arr[i][j] = 0; //取出Ai,并把arr[i][j]归零(删除标记)
        
        for(int j = 0; j < 10; j++){
            arr[i][(j + temp) % 10] = (arr[i][(j + temp) % 10] + arr[i-1][j]) % mod;
            arr[i][(j * temp) % 10] = (arr[i-1][j] + arr[i][(j * temp) % 10]) % mod;
        }
    }
    
    for(int i = 0; i < 10; i++)
        cout << arr[n][i] << endl;

    return 0;
}
posted @ 2021-09-28 20:28  伍六柒-  阅读(114)  评论(1)    收藏  举报