DP 杨老师的照相排列 、矩阵

杨老师的照相排列
在这里插入图片描述
输入样例:
1
30
5
1 1 1 1 1
3
3 2 1
4
5 3 3 1
5
6 5 4 3 2
2
15 15
0
输出样例:
1
1
16
4158
141892608
9694845

在这里插入图片描述

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 31;

int n;
LL f[N][N][N][N][N];

int main()
{
    while (cin >> n, n)
    {
        int s[5] = {0};
        for (int i = 0; i < n; i ++ ) cin >> s[i];
        memset(f, 0, sizeof f);
        f[0][0][0][0][0] = 1;

        for (int a = 0; a <= s[0]; a ++ )
            for (int b = 0; b <= min(a, s[1]); b ++ )
                for (int c = 0; c <= min(b, s[2]); c ++ )
                    for (int d = 0; d <= min(c, s[3]); d ++ )
                        for (int e = 0; e <= min(d, s[4]); e ++ )
                        {
                            LL &x = f[a][b][c][d][e];
                            if (a && a - 1 >= b) x += f[a - 1][b][c][d][e];
                            if (b && b - 1 >= c) x += f[a][b - 1][c][d][e];
                            if (c && c - 1 >= d) x += f[a][b][c - 1][d][e];
                            if (d && d - 1 >= e) x += f[a][b][c][d - 1][e];
                            if (e) x += f[a][b][c][d][e - 1];
                        }
        cout << f[s[0]][s[1]][s[2]][s[3]][s[4]] << endl;
    }

    return 0;
}

详细解析:

acwing解析

矩阵

问题描述
把 1 ∼ 2020 放在 2 × 1010 的矩阵里。

要求同一行中右边的比左边大,同一列中下边的比上边的大。一共有多少种方案?

答案很大,你只需要给出方案数除以 2020 的余数即可。

答案提交
这是一道结果填空题,你只需要算出结果后提交即可。
本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

答案:1340

分析
要放当前数字并使其递增,只能放两个位置,就是第一行最右边的空格处和第二行最右边的空格处。
动态规划
f[i][j] 表示第一行有i个数,第二行有j个数的方式总数。

方程式:
f[ i ] [ j ] += f[i - 1][ j ] , f[ i ] [ j ] += f [ i ] [ j - 1 ] ,
表示第一行有i个数第二行有j个数,可以由两种方式得到:
第一种:当第一行有i-1个数,第二行有j个数时,在第一行添加一个数就可以得到f[i][j]。
第一种:当第一行有i个数,第二行有j-1个数时,在第二行添加一个数就可以得到f[i][j]。

#include <iostream>
using namespace std;

int dp[1020][1020];

int main()
{
    dp[0][0] = 1; //设置初始值,一二行都不放数字时是一种方式。                                  // 两行一个数字都不放,也是一种方案
    for (int i = 0; i <= 1010; i ++)
        for (int j = 0; j<=1010&&j <= i; j ++)
        {
        	//加if判断数组下表不为负数 
            if(i - 1 >= 0)       // 转移前的状态也要合法,即第一行的数量不小于第二行的数量
            	dp[i][j] += dp[i - 1][j] % 2020;
            if(j - 1 >= 0)
            	dp[i][j] += dp[i][j - 1] % 2020;
        }
    cout << dp[1010][1010] << endl;   
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值