Dp46道和近期小结

最近做题比较散漫,无脑。中间打了个校赛,弱弱的水了几题,然后就挂机了,最后一个半小时都在酱油,结果也不是很好。

中间大概有三场bc是爆零了,快浅绿了。cf 打了两场只有only div2的,还好比较容易涨,大号终于紫了。

Hdu Dp入门题总结,时间隔的比较长,大概有一个月了。。网上写的也比较详细,这6题还是记忆犹新的,其他的就不说了。

 Cstructing Roads http://acm.hdu.edu.cn/showproblem.php?pid=1025 

以前做过,按照一维排序,另一位用nlogn的LIS做法做。写的时候,发现线段树可以搞,按照其中一维排序以后,

在另一维上建树,每个点的值表示这个点之前的最多连线对包括这个点。更新的时候,找到这个点之前的最大值,然后

最大值加一更新到这个点上。线段树维护一下区间最大值。

/* ***********************************************

    Author        : 一个西瓜

    Mail          : [email protected]

    Created Time  : 2015-04-14 20:32:08

    Problem       : Constructing Roads In JGShining's Kingdom

    ************************************************ */

#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <string>

#include <vector>

#include <cmath>

#include <queue>

#include <map>

#include <set>

using namespace std;

#define INF 1000000000

//typedef __int64 LL; 

#define lson l,mid,rt<<1

#define rson mid+1,r,rt<<1|1



const int maxn = 555555 + 10;

int sum[maxn << 2];

void build(int l, int r, int rt)

{

    sum[rt] = 0;

    if (l == r) return;

    int mid = (l + r) >> 1;

    build(lson); build(rson);

}

void up(int rt)

{

    sum[rt] = max(sum[rt << 1], sum[rt << 1 | 1]);

}



void update(int key, int add, int l, int r, int rt)

{

    if (l == r){

        sum[rt] = add; return;

    }

    int mid = (l + r) >> 1;

    if (key <= mid) update(key, add, lson);

    else update(key, add, rson);

    up(rt);

}



int ask(int L, int R, int l, int r, int rt)

{

    if (L <= l&&r <= R) return sum[rt];

    int ans = -1;

    int mid = (l + r) >> 1;

    if (L <= mid) ans = max(ans, ask(L, R, lson));

    if (R > mid) ans = max(ans, ask(L, R, rson));

    return ans;

}



struct Node

{

    int x; int y;

}node[maxn];



int cmp(const Node &a, const Node &b)

{

    if (a.x == b.x) return a.y < b.y;

    return a.x < b.x;

}



int main()

{

    int n;

    int Icase = 0;

    while (cin >> n){

        build(1, n, 1);

        for (int i = 1; i <= n; i++) scanf("%d%d", &node[i].x, &node[i].y);

        int Max = -1;

        sort(node + 1, node + 1 + n, cmp);

        for (int i = 1; i <= n; i++){

            int t = ask(1, node[i].y, 1, n, 1);

            Max = max(Max, t + 1);

            update(node[i].y, t + 1, 1, n, 1);

        }

        //if (Icase) putchar('\n');

        Icase++;

        printf("Case %d:\n", Icase);

        if (Max == 1)

            printf("My king, at most %d road can be built.\n", Max);

        else

            printf("My king, at most %d roads can be built.\n", Max);

        cout << endl;

    }

    return 0;

}
View Code

Humble Numbers http://acm.hdu.edu.cn/showproblem.php?pid=1058 

dp[n] = min(2*dp[i],3*dp[j],5*dp[k],7*dp[l]; 哪个最小, 哪个下标加一

/* ***********************************************

Author        : wtmlon

Mail          : [email protected]

Created Time  : 2015-03-27 19:42:09

Problem       : Humble Numbers

************************************************ */

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <string>

#include <vector>

#include <cmath>

#include <queue>

#include <map>

#include <set>

using namespace std;

#define INF 1000000000

//typedef __int64 LL; 



int f[111111];

int Min(int a, int b, int c, int d)

{

    return min(min(a, b), min(c, d));

}

int gao(int a, int b, int c, int d)

{

    int a1 = f[a] * 2; int b1 = f[b] * 3; int c1 = f[c] * 5; int d1 = f[d] * 7;

    int t = Min(a1, b1, c1, d1);

    if (t == a1) return 1;

    if (t == b1) return 2;

    if (t == c1) return 3;

    return 4;

}



int main()

{

    int n;

    int  l2 = 1, l3 = 1, l5 = 1, l7 = 1;

    f[1] = 1;

    for (int i = 2; i <= 5842; i++){

        int t = gao(l2, l3, l5, l7);

        if (t == 1){

            int k = f[l2] * 2;

            if (k == f[i - 1]) {

                i--; l2++; continue;

            }

            f[i] = k; l2++;

        }

        if (t == 2){

            int k = f[l3] * 3;

            if (k == f[i - 1]){

                i--; l3++; continue;

            }

            f[i] = k; l3++;

        }

        if (t == 3){

            int k = f[l5] * 5;

            if (k == f[i - 1]){

                i--; l5++; continue;

            }

            f[i] = k; l5++;

        }

        if (t == 4){

            int k = f[l7] * 7;

            if (k == f[i - 1]){

                i--; l7++; continue;

            }

            f[i] = k; l7++;

        }

    }

    while (cin >> n&&n){

        int k = n%100;

        if(k>=10&&k<=20){

            printf("The %dth humble number is %d.\n",n,f[n]);

        }

        else{

            k = k%10;

            if(k==1){

                printf("The %dst humble number is %d.",n,f[n]);

            }

            else if(k==2){

                printf("The %dnd humble number is %d.",n,f[n]);

            }

            else if(k==3){

                printf("The %drd humble number is %d.",n,f[n]);

            }

            else printf("The %dth humble number is %d.",n,f[n]);

            cout<<endl;

        }

    }

    return 0;

}
View Code

Fast Food http://acm.hdu.edu.cn/showproblem.php?pid=1227

搜的题解发现中位数距离最短,然后就能写了。顺便学了下带权中位数,就是一样的,把权值当成个数,然后按照大小排序过以后,权值从头开始加找到恰好大于所有权值和w的一半时的那个点,这个点到其他所有点的带权曼哈顿距离和最小。可以求多维的情况,因为是曼哈顿距离,所以不同维度的距离和是相互独立的。

/* ***********************************************

Author        : 一个西瓜

Mail          : [email protected]

Created Time  : 2015-04-19 14:47:52

Problem       : Fast Food

************************************************ */



#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <string>

#include <vector>

#include <cmath>

#include <queue>

#include <map>

#include <set>

using namespace std;

#define INF 1000000000

//typedef __int64 LL; 



int a[222];

int sum[222];

int dp[222][222];



int cost(int x, int y)

{

    int t = (x + y) / 2;

    int ans = 0;

    for (int i = x; i <= y; i++){

        ans += abs(a[i] - a[t]);

    }

    return ans;

}



int main()

{

    int Icase = 0;

    int n, k;

    while (cin >> n >> k, n || k){

        for (int i = 1; i <= n; i++){

            scanf("%d", &a[i]);

        }

        printf("Chain %d\n", ++Icase);

        for (int i = 1; i <= n;i++)

        for (int j = 1; j <= k; j++) dp[i][j] = INF;

        /*for (int i = 1; i <= n; i++){

            for (int j = i + 1; j <= n; j++){

                int ans = 0;

                for (int k = i + 1; k < j; k++){

                    ans += min(a[k] - a[i], a[j] - a[k]);

                }

                cost[i][j] = ans;

            }

        }*/

        /*for (int i = 1; i <= n; i++){

            int ans = 0;

            for (int j = 1; j < i; j++){

                ans += a[i] - a[j];

            }

            dp[i][1] = ans;

        }*/

        for (int i = 1; i <= n; i++) dp[i][1] = cost(1, i);

        for (int i = 2; i <= k; i++){

            for (int j = 1; j <= n; j++){

                for (int l = i - 1; l < j; l++){

                    dp[j][i] = min(dp[j][i], dp[l][i - 1] + cost(l+1,j));

                }

            }

        }

        printf("Total distance sum = %d\n\n", dp[n][k]);

    }

    return 0;

}
View Code

Regular Words http://acm.hdu.edu.cn/showproblem.php?pid=1502

抄了个大数模板卡过, dp[i][j][k] = dp[i-1][j][k] + dp[i][j-1][k] + dp[i][j][k-1];

/* ***********************************************

Author        : 一个西瓜

Mail          : [email protected]

Created Time  : 2015-04-20 10:12:04

Problem       : Regular Words

************************************************ */



#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <string>

#include <vector>

#include <cmath>

#include <queue>

#include <map>

#include <set>

using namespace std;

#define INF 1000000000

//typedef __int64 LL; 

typedef long long LL;

//套了个大数模板卡过。



struct BigInt {

    const static int mod = 10000;

    const static int DLEN = 4;

    int a[30], len;

    BigInt() {

        memset(a, 0, sizeof(a));

        len = 1;

    }

    BigInt(int v) {

        memset(a, 0, sizeof(a));

        len = 0;

        do

        {

            a[len++] = v%mod;

            v /= mod;

        } while (v);

    }

    BigInt(const char s[]) {

        memset(a, 0, sizeof(a));

        int L = strlen(s);

        len = L / DLEN;

        if (L%DLEN)len++;

        int index = 0;

        for (int i = L - 1; i >= 0; i -= DLEN) {

            int t = 0;

            int k = i - DLEN + 1;

            if (k < 0)k = 0;

            for (int j = k; j <= i; j++)

                t = t * 10 + s[j] - '0';

            a[index++] = t;

        }

    }

    BigInt operator +(const BigInt &b)const {

        BigInt res;

        res.len = max(len, b.len);

        for (int i = 0; i <= res.len; i++)

            res.a[i] = 0;

        for (int i = 0; i < res.len; i++) {

            res.a[i] += ((i < len) ? a[i] : 0) + ((i < b.len) ? b.a[i] : 0);

            res.a[i + 1] += res.a[i] / mod;

            res.a[i] %= mod;

        }

        if (res.a[res.len] > 0)res.len++;

        return res;

    }

    BigInt operator *(const BigInt &b)const {

        BigInt res;

        for (int i = 0; i < len; i++) {

            int up = 0;

            for (int j = 0; j < b.len; j++) {

                int temp = a[i] * b.a[j] + res.a[i + j] + up;

                res.a[i + j] = temp%mod;

                up = temp / mod;

            }

            if (up != 0)

                res.a[i + b.len] = up;

        }

        res.len = len + b.len;

        while (res.a[res.len - 1] == 0 && res.len > 1)res.len--;

        return res;

    }

    void output() {

        printf("%d", a[len - 1]);

        for (int i = len - 2; i >= 0; i--)

            printf("%04d", a[i]);

        printf("\n");

    }

}dp[61][61][61];

int main()

{

    int n;

    BigInt gg(1);

    dp[0][0][0] = dp[0][0][0] + gg;

    for (int i = 1; i <= 60; i++){

        for (int j = 0; j <= i; j++){

            for (int k = 0; k <= j; k++){

                if (i - 1 >= j) dp[i][j][k] =dp[i][j][k] + dp[i - 1][j][k];

                if (j - 1 >= k) dp[i][j][k] =dp[i][j][k] + dp[i][j - 1][k];

                if (k - 1 >= 0) dp[i][j][k] =dp[i][j][k] + dp[i][j][k - 1];

            }

        }

    }

    while (cin >> n){

        dp[n][n][n].output();

        cout << endl;

    }

    return 0;

}
View Code

Doing Homework Again http://acm.hdu.edu.cn/showproblem.php?pid=1789 

按截止日期从小到大排个序,然后dp[i][j] 表示第i个任务当前时间为j的最多得的分

dp[i][j] = max(dp[i-1][j] , dp[i-1][j-1] + val[i]); j这天做不做第i个任务中间的最多得分.

拿总的分数减下,就是最少的要扣的分数。

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <string>

#include <vector>

#include <cmath>

#include <queue>

#include <map>

#include <set>

using namespace std;

#define INF 1000000000

//typedef __int64 LL;

const int maxn = 1111;

struct Node

{

    int x; int y;

}node[maxn];



int cmp(const Node &a, const Node &b)

{

    if (a.x == b.x) return a.y < b.y; 

    return a.x < b.x;

}

int dp[maxn][maxn];



int main()

{

    int T,n;

    cin >> T;

    while (T--){

        cin >> n;

        int sum = 0; int Max = -1;

        for (int i = 1; i <= n; i++) scanf("%d", &node[i].x);

        for (int i = 1; i <= n; i++) scanf("%d", &node[i].y), sum += node[i].y;

        sort(node + 1, node + 1 + n, cmp);

        memset(dp,0,sizeof(dp));

        for (int i = 1; i <= n; i++){

            for (int j = 1; j <= node[i].x; j++){

                dp[i][j] = max(dp[i - 1][j - 1] + node[i].y, dp[i - 1][j]);

                Max = max(dp[i][j], Max);

            }

        }

        cout << sum - Max << endl;

    }

    return 0;

}
View Code

Employment Planning http://acm.hdu.edu.cn/showproblem.php?pid=1158 

我猜测能雇佣人数的取值范围就是每个月要求的人数的取值,所以最后就是一个n^2的dp,然后就过了。

/* ***********************************************

Author        : 一个西瓜

Mail          : [email protected]

Created Time  : 2015-04-15 20:53:26

Problem       : Employment Plannin

************************************************ */



#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <string>

#include <vector>

#include <cmath>

#include <queue>

#include <map>

#include <set>

using namespace std;

#define INF 1000000000

//typedef __int64 LL; 

int a[100];

int dp[30][30];

int main()

{

    int n;

    int hire, salary, fire;

    while (scanf("%d", &n) && n){

        scanf("%d%d%d", &hire, &salary, &fire);

        for (int i = 0; i <= n; i++)

        for (int j = 0; j <= n; j++)

            dp[i][j] = INF;

        dp[0][0] = 0;

        a[0] = 0;

        int Min = INF;

        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);

        for (int i = 1; i <= n; i++){

            for (int j = 0; j <= n; j++){

                if (a[j] < a[i]) continue;

                for (int k = 0; k <= n; k++){

                    int b = a[j]; int c = a[k];

                    if (b >= c){

                        dp[i][j] = min(dp[i][j], dp[i - 1][k] + b*salary + (b - c)*hire);

                    }

                    else{

                        dp[i][j] = min(dp[i][j], dp[i - 1][k] + (c - b)*fire + b*salary);

                    }

                    //if (i == 2 && j == 2) printf("%d %d %d %djiji\n", b,c,dp[i][j],dp[i-1][]);

                }

                //cout << i << " " << j << " " << dp[i][j] << endl;

            }

        }

        for (int i = 1; i <= n; i++) Min = min(Min, dp[n][i]);

        cout << Min << endl;

    }

    return 0;

}
View Code

 

你可能感兴趣的:(dp)