分类目录归档:动态规划

洛谷 计算系数

题号: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;
}

洛谷 守望者的逃离

洛谷题号: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;
}

洛谷/USACO 01串 Stringsobits

洛谷题号:P2727
参考题解:作者: 罗进瑶 更新时间: 2017-08-04 10:49 https://www.luogu.org/wiki/show?name=%E9%A2%98%E8%A7%A3+P2727

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
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include<cassert>
#include<map>
#include<queue>
using namespace std;
long long dp[40][40];//dp[i][j]表示长度为i,最多含有j个1的二进制数的个数
int main(){
    ios::sync_with_stdio(false);
    long long n, l, i;
    cin >> n >> l >> i;
    for (int i = 0; i <= n; i++)dp[i][0] = dp[0][i] = 1;
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= l; j++){
            dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
        }
    }
    long long k = i;
    for (int i = n; i >= 1; i--){
        if (k > dp[i - 1][l]){
            cout << "1";
            k -= dp[i - 1][l];
            l--;
        }
        else cout << "0";
    }
    cout << endl;
}

洛谷 奶牛家谱 Cow Pedigrees

毫不夸张的说:USACO里2.3节最难的动规、、、
基本是照着题解一个字一个字对的。。。。
题号:1472

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<cstdlib>
#include<cstring>
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#define MOD 9901
using namespace std;
int n, k;
long long f[210][110],dp[210][110]; //必须是long long
int main(){
    cin >> n >> k;
    //if (n % 2 == 0){
    //  cout << 0 << endl;
    //  return 0;
    //}
    dp[1][1] = 1; f[0][0] = 1;
    for (int i = 1; i <= k; i++)f[1][i] = f[0][i] = 1;
    for (int i = 3; i <= n; i += 2){ //i:Node Num;j:depth
        int j = 1; while ((1 << j) - 1 < i)j++;
        for (; j <= k; j++){
            for (int l = 1; l <= i - 1; l += 2){
                dp[i][j] += dp[l][j - 1] * f[i - l - 1][j - 2];
                dp[i][j] += f[l][j - 2] * dp[i - l - 1][j - 1];
                dp[i][j] += dp[l][j - 1] * dp[i - l - 1][j - 1];
            }
            dp[i][j] %= MOD;
        }
        for (int j = 1; j <= k; j++)f[i][j] = (f[i][j - 1] + dp[i][j]) % MOD;
    }
    cout << dp[n][k] << endl;
}

洛谷 过河

题号:1052
参考题解:
https://www.luogu.org/wiki/show?name=%E9%A2%98%E8%A7%A3+P1052
作者: CoolTeam 更新时间: 2015-08-11 18:26
作者: shutdown 更新时间: 2013-07-30 20:20
作者: VengefulSpirit 更新时间: 2013-06-25 11:17
作者: sb123 更新时间: 2017-08-07 17:58

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
#include<iostream>
#include<algorithm>
#include<string>
#include<utility>
#include<queue>
#include<cstdlib>
#include<cstring>
#include<map>
using namespace std;
int f[20005];
int Mk[105],M[105];
//ifstream cin("in.txt");
//ofstream cout("out.txt");
int main(){
    ios::sync_with_stdio(false);
    int l, s, t, m,ans=0;
    cin >> l >> s >> t >> m;
    for (int i = 1; i <= m; i++){
        cin >> Mk[i];//存入M的临时数组
    }
    if (s == t){//当s==t时是特殊情况,只需判断为s/t倍数的点有无石子即可 ;参考CoolTeam。为啥用动态规划过不了,我也不知道
        for (int i = 1; i <= m; i++){
            if (Mk[i] % s == 0)ans++;
        }
        cout << ans;
        return 0;
    } //否则需要使用动态规划
    memset(f, 0x7f, sizeof(f));
    f[0] = 0;
    sort(Mk + 1, Mk + m + 1); //先给临时数组排个序
    for (int i = 1; i <= m; i++){
        if (Mk[i] - Mk[i - 1] >= 100)M[i] = M[i - 1] + 100; //如果两相邻石子之间距离大于100,就将他们之间的距离缩小到100 ;参考shutdown的结论,VengefulSpirit的证明过程
        else M[i] = M[i - 1] + Mk[i] - Mk[i - 1];
    }
    int M_cnt = 1;
    for (int i = 1; i <= M[m]+t; i++){ //比较容易的动态规划 ;参考sb123的动规转移方程
        for (int j = i-s; j >= max(i - t,0); j--){
            f[i] = min(f[j], f[i]);
        }
        if (M[M_cnt] == i){
            f[i]++;
            M_cnt++;
        }
    }
    ans = 10000;
    for (int i = M[m] + t-1; i >= M[m]; i--)ans = min(ans, f[i]);  //遍历从最后一个石子到最后一个石子+t-1的最短距离
    cout << ans;
}