分类目录归档:动态规划

洛谷 P1164 小A点菜

这动规没见过,不好做……参考题解了……
https://www.luogu.org/blog/DEDSECspace/solution-p1164
https://www.luogu.org/blog/6-28318530717958/solution-p1164

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<deque>
#include<map>
#include<cstring>
using namespace std;
int n, m;
int A[105];
int f[10005];
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)cin >> A[i];
    f[0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = m; j >= A[i]; j--) {
            f[j]+= f[j - A[i]];
        }
    }
    cout << f[m];
}

洛谷 P1060 开心的金明

Ver1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<deque>
#include<map>
#include<cstring>
using namespace std;
int n, m;
int v[30],w[30];//乘积,价格
int f[30][30005]; //物品,钱数
int main() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int tmp2;
        cin >> w[i] >> tmp2;
        v[i] = w[i] * tmp2;
    }
    for (int i = 1; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            if(j>=w[i])f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
            else f[i][j] = f[i - 1][j];
        }
    }
    int mmax = 0;
    for (int i = 0; i <= n; i++) {
        mmax = max(mmax, f[m][i]);
    }
    cout << mmax;
}

Ver2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<deque>
#include<map>
#include<cstring>
using namespace std;
int n, m;
int v[30],w[30];//乘积,价格
int f[30005]; //钱数
int main() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int tmp2;
        cin >> w[i] >> tmp2;
        v[i] = w[i] * tmp2;
    }
    for (int i = 1; i <= m; i++) {
        for (int j = n; j >=w[i]; j--) {
            f[j] = max(f[j], f[j - w[i]] + v[i]);
        }
    }
    int mmax=0;
    for (int i = 0; i <= n; i++) {
        mmax = max(mmax, f[i]);
    }
    cout << mmax;
}

洛谷 P1115 最大子段和

严格注意语句顺序不能改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int A[200005];
int mmax = 0x80000000;
int main() {
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n; i++)cin >> A[i];
    int curSum = 0;
    for (int i = 1; i <= n; i++) {
        curSum += A[i];
        mmax = max(mmax, curSum);
        if (curSum < 0)curSum = 0;
    }
    cout << mmax;
}

Codeforces Round #494 (Div. 3) 1003 B题 Binary String Constructing 构建二进制字符串 题解

简明题意:用a个0,b个1构建出长度为n=a+b的字符串s,且对于$0 < i < n$,有$s_i != s_{i-1}$的i的个数恰为x。
当时比赛的时候没做出来,估计就是要写搜索一类的就先跳过了。后来再来写这道题目。

所以今天改了三遍。没有看任何题解。第一版:递归,第二版:递推/迭代(动规),第三版:递推(动规)+滚动数组优化。真的不知道我是怎么想起来N长时间之前背包问题里的滚动数组优化了。感觉自己特别厉害好长时间都没写了这都能想的起来。第三版程序终于有了让人没有文字说明就完全看不懂想不明白的资本啦,哈哈^v^

第一版:递归,没有任何记忆化措施,所以TLE了,然后就想着把递归换成递推。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<iostream>
#include<algorithm>
using namespace std;
int a, b, x;
char str[105];
bool recusive(int curpos, int cura, int curb, int curx) {
    if (curpos == a + b) {
        if (cura == a && curb == b && curx == x) {
            str[curpos] = '\0';
            return true;
        }
        else return false;
    }
    if ((cura == a || curb == b)&&curx==x) {
        if (cura == a) {
            for (int i = curpos; i < a + b; i++)str[i] = '1';
            str[a + b] = '\0';
            return true;
        }
        else {
            for (int i = curpos; i < a + b; i++)str[i] = '0';
            str[a + b] = '\0';
            return true;
        }
    }
    //Assume curpos==0
    str[curpos] = '0';
    bool flag = false;
    if (curpos == 0 || str[curpos - 1] == '0')flag = recusive(curpos + 1, cura + 1, curb, curx);
    else flag = recusive(curpos + 1, cura + 1, curb, curx + 1);
    if (flag)return true;
    str[curpos] = '1';
    if (curpos == 0 || str[curpos - 1] == '1')flag = recusive(curpos + 1, cura, curb + 1, curx);
    else flag = recusive(curpos + 1, cura, curb + 1, curx + 1);
    if (flag)return true;
    return false;
}
int main() {
    cin >> a >> b >> x;
    recusive(0, 0, 0, 0);
    cout << str;
}

第二版:递推。没有任何优化,时间够了,但是内存不够MLE了。四个维度分别是a,b,x,上个字符串的最后一个数字是0还是1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int a, b, x;
string arr[101][101][201][2]; //a,b,x,
int main() {
    cin >> a >> b >> x;
    for (int i = 1; i <= a; i++)arr[i][0][0][0] = arr[i - 1][0][0][0] + '0';
    for (int i = 1; i <= b; i++)arr[0][i][0][1] = arr[0][i - 1][0][1] + '1';
    for (int k = 1; k <= x; k++) { //curx
        for (int i = 1; i <= a; i++) { //cura
            for (int j = 1; j <= b; j++) { //curb
                //Assume to place a 0
                if (arr[i - 1][j][k - 1][1] != "")arr[i][j][k][0] = arr[i - 1][j][k - 1][1] + '0';
                else if (arr[i - 1][j][k][0] != "")arr[i][j][k][0] = arr[i - 1][j][k][0] + '0';
                //Assume to place a 1
                if (arr[i][j - 1][k - 1][0] != "")arr[i][j][k][1] = arr[i][j - 1][k - 1][0] + '1';
                else if (arr[i][j - 1][k][1] != "")arr[i][j][k][1] = arr[i][j - 1][k][1] + '1';
            }
        }
    }
    if (arr[a][b][x][0] != "")cout << arr[a][b][x][0];
    else cout << arr[a][b][x][1];
}

第三版:递推+滚动数组。把第三维由201优化到只剩2。因为动规的转移方程里面只需要上一个k和当前k的数组,所以滚动数组优化一下就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int a, b, x;
string arr[101][101][2][2];
inline int trans(int num) {
    if (num % 2 == 0)return 0;
    else return 1;
}
int main() {
    cin >> a >> b >> x;
    for (int i = 1; i <= a; i++)arr[i][0][0][0] = arr[i - 1][0][0][0] + '0';
    for (int i = 1; i <= b; i++)arr[0][i][0][1] = arr[0][i - 1][0][1] + '1';
    for (int k = 1; k <= x; k++) { //curx
        for(int i=0;i<=a;i++)for(int j=0;j<=b;j++)for(int m=0;m<=1;m++)arr[i][j][trans(k)][m]=""; //Clean the rolling array to prevent unexpected error
        for (int i = 1; i <= a; i++) { //cura
            for (int j = 1; j <= b; j++) { //curb
                //Assume to place a 0
                if (arr[i - 1][j][trans(k - 1)][1] != "")arr[i][j][trans(k)][0] = arr[i - 1][j][trans(k - 1)][1] + '0';
                else if (arr[i - 1][j][trans(k)][0] != "")arr[i][j][trans(k)][0] = arr[i - 1][j][trans(k)][0] + '0';
                else arr[i][j][trans(k)][0]="";
                //Assume to place a 1
                if (arr[i][j - 1][trans(k - 1)][0] != "")arr[i][j][trans(k)][1] = arr[i][j - 1][trans(k - 1)][0] + '1';
                else if (arr[i][j - 1][trans(k)][1] != "")arr[i][j][trans(k)][1] = arr[i][j - 1][trans(k)][1] + '1';
                else arr[i][j][trans(k)][1]="";
            }
        }
    }
    if (arr[a][b][trans(x)][0] != "")cout << arr[a][b][trans(x)][0];
    else cout << arr[a][b][trans(x)][1];
}

写了我三个小时,也是挺不容易的……继续努力!写的不清楚有问题可以在下面评论问。

洛谷 计算系数

题号:P1313
大晚上的刷杨辉三角………………

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<list>
#include<cstring>
#include<cassert>
#include<cmath>
using namespace std;
#define MOD 10007
long long arr[1005][1005];
long long a, b, k, n, m;
long long quickpow(long long x, long long y){
    if (y == 0)return 1;
    long long qpsqr2 = quickpow(x, y / 2)%MOD;
    if (y % 2 == 0){
        return (qpsqr2*qpsqr2) % MOD;
    }
    else{
        return (((qpsqr2*qpsqr2) % MOD)*(x%MOD)) % MOD;
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin >> a >> b >> k >> n >> m;
    for (int i = 0; i <= 1000; i++){
        arr[0][i] = 1;
        arr[i][i] = 1;
    }
    for (int i = 1; i <= 1000; i++){
        for (int j = 1; j < i; j++){
            arr[j][i] = (arr[j][i - 1] % MOD + arr[j - 1][i - 1] % MOD) % MOD;
        }
    }
    long long ans = arr[n][k];
    ans = (ans*quickpow(a, n)) % MOD;
    ans = (ans*quickpow(b, m)) % MOD;
    cout << ans;
    return 0;
}

20180808更新:
不用杨辉三角啦!因为我会乘法逆元啦!!!哈哈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
#define ll long long
#define pii pair<int,int>
#define PINF 0x7fffffff
#define NINF 0x80000000
using namespace std;
#define MOD 10007
ll a,b,k,n,m;
//C(min(n,m),k)*b^m*a^n
ll quickpow(ll a, ll b) {
    if (b == 0)return 1;
    ll re = quickpow(a, b / 2) % MOD;
    re = (re*re) % MOD;
    if (b % 2 == 1)re *= a % MOD;
    return re % MOD;
}
ll inv(ll x) {
    return quickpow(x, MOD - 2) % MOD;
}
int main() {
    cin >> a >> b >> k >> n >> m;
    ll re = (quickpow(a, n)*quickpow(b, m)) % MOD;
    ll cU = 1;
    for (ll i = k; i >= k - min(n, m) + 1; i--) {
        cU *= i % MOD;
        cU %= MOD;
    }
    ll cD = 1;
    for (ll i = 1; i <= min(n, m); i++) {
        cD *= i % MOD;
        cD %= MOD;
    }
    re = ((re * cU) % MOD*inv(cD)) % MOD;
    cout << re;
}

洛谷 守望者的逃离

洛谷题号:P1095
参考题解:作者: 究极龙骑士 更新时间: 2017-07-11 22:44 https://www.luogu.org/wiki/show?name=%E9%A2%98%E8%A7%A3+P1095

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<list>
#include<cstring>
#include<cassert>
#include<cmath>
using namespace std;
int m, s, t;
int main(){
    ios::sync_with_stdio(false);
    cin >> m >> s >> t;
    int s1 = 0, s2 = 0;//s1跑步,s2瞬间移动
    for (int time = 1; time <= t; time++){
        s1 += 17;
        if (m >= 10){
            m -= 10;
            s2 += 60;
        }
        else{
            m += 4;
        }
        if (s1 < s2)s1 = s2;
        if (s1> s){
            cout << "Yes" << endl << time << endl;
            return 0;
        }
    }
    cout << "No" << endl << s1 << endl;
    return 0;
}

洛谷10月月赛R1·浴谷八连测R1·提高组 SAC E#1 – 一道简单题 Sequence2

洛谷题号:P3928
就写60分的代码(仿照LIS),不想写100分(线段树不会)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<list>
#include<cstring>
#include<cassert>
#include<cmath>
using namespace std;
int n;
long long a[5][100050];//把数列看成4行,原来的第三行分为两行,只能连续大于等于(3)或小于等于(4),不能转移
long long dp[5][100050];//dp[i][j]表示从第i行选择第j个数的最长波动序列长度
int main(){
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= 3; i++){
        for (int j = 1; j <= n; j++){
            cin >> a[i][j];
        }
    }
    for (int i = 1; i <= n; i++){//将第三行的数复制到第四行
        a[4][i] = a[3][i];
    }
    //dp初始化
    for (int i = 1; i <= 5; i++){
        dp[i][1] = 1;
    }
    //dp转移方程
    for (int j = 2; j <= n; j++){//第j个数
        for (int k = 1; k < j; k++){ //和LIS相同
            //第一行
            for (int i = 1; i <= 4; i++){
                if (a[1][j] >= a[i][k])dp[1][j] = max(dp[1][j], dp[i][k] + 1);
            }
            //第二行
            for (int i = 1; i <= 4; i++){
                if (a[2][j] <= a[i][k])dp[2][j] = max(dp[2][j], dp[i][k] + 1);
            }
            //第三行
            for (int i = 1; i <= 3; i++){
                if (a[3][j] >= a[i][k])dp[3][j] = max(dp[3][j], dp[i][k] + 1);
            }
            //第四行
            for (int i = 1; i <= 4; i++){
                if (i == 3)continue;
                if (a[4][j] <= a[i][k])dp[4][j] = max(dp[4][j], dp[i][k] + 1);
            }
        }
    }
    long long ans = 0;
    for (int i = 1; i <= 4; i++){
        ans = max(ans, dp[i][n]);
    }
    cout << ans << endl;
    return 0;
}

洛谷/USACO “破锣摇滚”乐队 Raucous Rockers

洛谷题号:P2736
又是动规,只会DFS……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<list>
#include<cstring>
#include<cassert>
using namespace std;
int n, t, m;
int song[25];
int dfs(int cur_song, int cur_cd, int rem_min){
    if (cur_song == n + 1){
        if (cur_cd <= m){
            return 0;
        }
        return -2e9;
    }
    if (song[cur_song] <= rem_min){
        return max(dfs(cur_song + 1, cur_cd, rem_min), dfs(cur_song + 1, cur_cd, rem_min - song[cur_song]) + 1);
    }
    else{//song[cur_song]>rem_min
        return max(dfs(cur_song + 1, cur_cd, rem_min), dfs(cur_song + 1, cur_cd + 1, t - song[cur_song]) + 1);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin >> n >> t >> m;
    for (int i = 1; i <= n; i++){
        cin >> song[i];
        if (song[i] > t){
            i--;
            n--;
        }
    }
    if (n == 0){
        cout << 0 << endl;
        return 0;
    }
    cout << dfs(1, 1, t) << endl;
}

洛谷/USACO 商店购物 Shopping Offers

洛谷题号:P2732
实在是被这五维的完全背包恶心了一把……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
int s, b;
int dp[6][6][6][6][6];
int goods[1000];
int buy[6];
struct plan{
    int n;
    int k[6];
    int p;
}plans[200];
int No = 0;
int main(){
    ios::sync_with_stdio(false);
    cin >> s;
    for (int i = 1; i <= s; i++){
        cin >> plans[i].n;
        for (int j = 1; j <= plans[i].n; j++){
            int ci, ki;
            cin >> ci >> ki;
            if (goods[ci] == 0)goods[ci] = ++No;
            plans[i].k[goods[ci]] = ki;
        }
        cin >> plans[i].p;
    }
    cin >> b;
    for (int i = 1; i <= b; i++){
        int ci, pi, ki;
        cin >> ci >> ki >> pi;
        if (goods[ci] == 0)goods[ci] = ++No;
        buy[goods[ci]] = ki;
        s++;
        plans[s].n = 1;
        plans[s].k[goods[ci]] = 1;
        plans[s].p = pi;
    }
    memset(dp, 0x7f, sizeof(dp));
    dp[0][0][0][0][0] = 0;
    for (int z = 1; z <= s; z++){
        for (int i = plans[z].k[1]; i <= buy[1]; i++){
            for (int j = plans[z].k[2]; j <= buy[2]; j++){
                for (int l = plans[z].k[3]; l <= buy[3]; l++){
                    for (int x = plans[z].k[4]; x <= buy[4]; x++){
                        for (int y = plans[z].k[5]; y <= buy[5]; y++){
                            dp[i][j][l][x][y] = min(dp[i][j][l][x][y], dp[i - plans[z].k[1]][j - plans[z].k[2]][l - plans[z].k[3]][x - plans[z].k[4]][y - plans[z].k[5]]+plans[z].p);
                        }
                    }
                }
            }
        }
    }
    cout << dp[buy[1]][buy[2]][buy[3]][buy[4]][buy[5]] << endl;
}

洛谷/USACO 游戏 A Game

洛谷题号:P2734
挺难的一道区间型动规,并不会做,看的题解,需要继续学习:
参考题解:https://www.luogu.org/wiki/show?name=%E9%A2%98%E8%A7%A3+P2734 作者: redbag 管理员 更新时间: 2016-08-12 11:04

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<list>
#include<cstring>
#include<cassert>
using namespace std;
int n;
int num[105],sum[105];
int f[105][105];
int main(){
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> num[i];
        sum[i] = sum[i - 1] + num[i];
        f[i][i] = num[i];
    }
    for (int i = n - 1; i >= 1; i--){
        for (int j = i + 1; j <= n; j++){
            f[i][j] = max(sum[j] - sum[i - 1] - f[i + 1][j], sum[j] - sum[i - 1] - f[i][j - 1]);
        }
    }
    cout << f[1][n] << " " << sum[n] - f[1][n] << endl;
}