dp 2016.7.29

来源:互联网 发布:怎样领淘宝内部优惠卷 编辑:程序博客网 时间:2024/06/05 12:49

1、Codeforces_2B The least round way

参考:http://www.cnblogs.com/zjbztianya/p/3271449.html

题意:

给定一个N*N的格子,每个格子里有一个非负数

要求你找出从左上角到右下角的一条路径,使得它满足路径上的格子里的数全部乘起来的积尾部0最少


解题思路:

如果要产生0肯定是2*5得出来的,最终的乘积可以表示为 2 ^ x * 5 ^ y * C,那么零的个数就是 min(x, y)

我们可以先对每个格子里的数预处理下,计算出2和5的个数来

然后 dp 分别求出 2 和 5 的最小个数然后选两者中的最小值,这个 dp 还是比较简单的

还有一个要注意的问题就是如果某个格子的数字为0的情况,这个需要特殊判断一下,我们可以把它当做10,如果最后的结果0的个数大于1则直接输出尾部0的个数为1即可

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;const ull mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 1e3 + 10;int n;int dp_2[maxn][maxn], dp_5[maxn][maxn];bool flag = false;int zero_x, zero_y;bool turn_2[maxn][maxn], turn_5[maxn][maxn];string s;int x;int main(){#ifdef __AiR_H    freopen("in.txt", "r", stdin);#endif // __AiR_H    scanf("%d", &n);    memset(dp_2, 0, sizeof(dp_2));    memset(dp_5, 0, sizeof(dp_5));    memset(turn_2, false, sizeof(turn_2)); //默认向下    memset(turn_5, false, sizeof(turn_5));    for (int i = 0; i < n; ++i) {        for (int j = 0; j < n; ++j) {            scanf("%d", &x);            if (x == 0) {                flag = true;                zero_x = i; zero_y = j;                dp_2[i][j] = dp_5[i][j] = 1;            } else {                while (!(x & 1)) {                    ++dp_2[i][j];                    x >>= 1;                }                while (x%5 == 0) {                    ++dp_5[i][j];                    x /= 5;                }            }        }    }    for (int i = 0; i < n; ++i) {        for (int j = 0; j < n; ++j) {            int t1 = INF, t2 = INF;            if (i == 0 && j == 0) {                t1 = t2 = 0;            }            if (i != 0 && dp_2[i-1][j] < t1) {                t1 = dp_2[i-1][j];            }            if (j != 0 && dp_2[i][j-1] < t1) {                t1 = dp_2[i][j-1];                turn_2[i][j] = true;            }            if (i != 0 && dp_5[i-1][j] < t2) {                t2 = dp_5[i-1][j];            }            if (j != 0 && dp_5[i][j-1] < t2) {                t2 = dp_5[i][j-1];                turn_5[i][j] = true;            }            dp_2[i][j] += t1;            dp_5[i][j] += t2;        }    }    int Min = min(dp_2[n-1][n-1], dp_5[n-1][n-1]);    if (flag && Min > 1) {        printf("1\n");        for (int i = 0; i < zero_y; ++i) {            printf("R");        }        for (int i = 0; i < zero_x; ++i) {            printf("D");        }        for (int i = zero_y; i < n-1; ++i) {            printf("R");        }        for (int i = zero_x; i < n-1; ++i) {            printf("D");        }        printf("\n");    } else {        int i = n-1, j = n-1;        if (Min == dp_5[n-1][n-1]) {            while (i > 0 || j > 0) {                if (turn_5[i][j]) {                    s += 'R';                    --j;                } else {                    s += 'D';                    --i;                }            }        } else {            while (i > 0 || j > 0) {                if (turn_2[i][j]) {                    s += 'R';                    --j;                } else {                    s += 'D';                    --i;                }            }        }        reverse(s.begin(), s.end());        cout << Min << endl;        cout << s << endl;    }    return 0;}

2、SGU 116 Index of super-prime

dp[j] 表示和为 j 时使用的最少的超级素数的个数

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;const ull mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 1e5 + 10;bool vis[maxn];int Count = 1;int Prime[9600];int Super[1200];int Super_Count = 0;int dp[maxn];int pre[maxn];int ans[maxn];int ans_Count = 0;void Init(void);bool cmp(int x, int y);int main(){#ifdef __AiR_H    freopen("in.txt", "r", stdin);//    freopen("out.txt", "w", stdout);#endif // __AiR_H    Init();    int N;    while (scanf("%d", &N) != EOF) {        memset(pre, 0, sizeof(pre));        memset(dp, 0, sizeof(dp));        ans_Count = 0;        int t = lower_bound(Super, Super+Super_Count, N) - Super;        for (int i = 0; i <= t; ++i) {            dp[Super[i]] = 1;            pre[Super[i]] = 0;            for (int j = 1; j <= N-Super[i]; ++j) {                if (dp[j] != 0) {                    if (dp[Super[i]+j] == 0 || dp[Super[i]+j] > dp[j] + 1) {                        dp[Super[i]+j] = dp[j] + 1;                        pre[Super[i]+j] = j;                    }                }            }        }        if (dp[N] == 0) {            printf("0\n");        } else {            int N_t = N;            while (N_t != 0) {                ans[ans_Count++] = N_t - pre[N_t];                N_t = pre[N_t];            }            printf("%d\n", ans_Count);            sort(ans, ans+ans_Count, cmp);            printf("%d", ans[0]);            for (int i = 1; i < ans_Count; ++i) {                printf(" %d", ans[i]);            }            printf("\n");        }    }    return 0;}void Init(void){    memset(vis, false, sizeof(vis));    for (int i = 2; i < maxn; ++i) {        if (!vis[i]) {            vis[i] = true;            Prime[Count++] = i;            int j = i*2;            while (j < maxn) {                vis[j] = true;                j += i;            }        }    }    for (int i = 1; i < Count; ++i) {        int t = lower_bound(Prime, Prime+Count, i) - Prime;        if (Prime[t] == i) {            Super[Super_Count++] = Prime[i];        }    }}bool cmp(int x, int y){    return (x > y);}


3、最大上升子序列和

描述

一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, ...,aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1 <= i1 < i2 < ... < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中序列和最大为18,为子序列(1, 3, 5, 9)的和.

你的任务,就是对于给定的序列,求出最大上升子序列和。注意,最长的上升子序列的和不一定是最大的,比如序列(100, 1, 2, 3)的最大上升子序列和为100,而最长上升子序列为(1, 2, 3)

输入
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000(可能重复)。
输出
最大上升子序列和
样例输入
71 7 3 5 9 4 8
样例输出
18

解题思路:

dp[j] 表示以 num[j] 结尾的最大上升子序列和


#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;const ull mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 1e3 + 10;int num[maxn];int N;int dp[maxn];int main(){#ifdef __AiR_H    freopen("in.txt", "r", stdin);#endif // __AiR_H    scanf("%d", &N);    for (int i = 0; i < N; ++i) {        scanf("%d", &num[i]);    }    memset(dp, 0, sizeof(dp));    int ans = 0;    for (int i = 0; i < N; ++i) {        int Max = 0;        for (int j = 0; j < i; ++j) {            if (num[j] < num[i]) {                if (dp[j] > Max) {                    Max = dp[j];                }            }        }        dp[i] = num[i] + Max;        if (dp[i] > ans) {            ans = dp[i];        }    }    printf("%d\n", ans);    return 0;}

4、HDU 5748 Bellovin

一道裸的 nlogn 的 LIS

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;const ull mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 1e5 + 10;int a[maxn];int n;int B[maxn];int dp[maxn];int main(){#ifdef __AiR_H    freopen("in.txt", "r", stdin);#endif // __AiR_H    int T;    scanf("%d", &T);    while (T--) {        scanf("%d", &n);        for (int i = 1; i <= n; ++i) {            scanf("%d", &a[i]);        }        int Count = 0;        memset(B, 0, sizeof(B));        memset(dp, 0, sizeof(dp));        for (int i = 1; i <= n; ++i) {            if (Count == 0 || a[i] > B[Count-1]) {                B[Count++] = a[i];                dp[i] = Count;            } else {                int pos = lower_bound(B, B+Count, a[i]) - B;                B[pos] = a[i];                dp[i] = pos+1;            }        }        printf("%d", dp[1]);        for (int i = 2; i <= n; ++i) {            printf(" %d", dp[i]);        }        printf("\n");    }    return 0;}

5、HDU 5763 Another Meaning

匹配用暴力(比如 string 类的 find)也能过,还可以用 KMP 或者其它方法

具体是怎么 dp 的我说不很清楚。。。所以干脆根据样例一步一步画出来了

当 A = hehehehe,B = hehe

dp[0] :
*hehe

dp[1] :
*hehe

dp[2] :
dp[i-1] :         *hehe
+1 :             he*he

dp[3] :
*hehe    he*he

dp[4] :
dp[i-1] :         *hehe    he*he
dp[i-len_B] :    **
+1 :            hehe*

dp[5] = dp[6] = d[7] :
*hehe    he*he    **    hehe*

ans:
dp[7] :         *hehe    he*he    **    hehe*
+1                hehehehe


当 A = aaaab,B = a

dp[0] :
*aaab

dp[1] :
+d[i-1] :         *aaab
+dp[i-len_B] :     **aab
+1 :             a*aab

dp[2] :
+dp[i-1] :         *aaab    **aab    a*aab
+dp[i-len_B] :    *a*ab     ***ab    a**ab
+1 :            aa*ab

dp[3] :            
+dp[i-1] :         *aaab    **aab    a*aab    *a*ab     ***ab    a**ab    aa*ab
+dp[i-len_B] :    *aa*b    ***ab    a*a*b    *a**b    ****b    a***b    aa**b
+1 :             aaa*b

dp[4] :
*aaab    **aab    a*aab    *a*ab     ***ab    a**ab    aa*ab    *aa*b    ***ab    a*a*b    *a**b    ****b    a***b    aa**b    aaa*b

ans :
dp[4] : *aaab    **aab    a*aab    *a*ab     ***ab    a**ab    aa*ab    *aa*b    ***ab    a*a*b    *a**b    ****b    a***b    aa**b    aaa*b
+1 :     aaaab

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>#include <bitset>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;typedef pair<int, int> Pair;const int mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 1e5 + 10;string A, B;bool vis[maxn];int dp[maxn];int main(){#ifdef __AiR_H    freopen("in.txt", "r", stdin);#endif // __AiR_H    int T;    scanf("%d", &T);    int Case= 0;    while (T--) {        memset(vis, false, sizeof(vis));        cin >> A >> B;        int len_B = B.length();        int len_A = A.length();        size_t pos = A.find(B, 0);        while (pos != string::npos) {            vis[pos] = true;            pos = A.find(B, pos+1);        }        for (int i = 0; i < len_A; ++i) {            if (vis[i]) {                if (i == 0) {                    dp[i] = 1;                } else if (i < len_B) {                    dp[i] = dp[i-1] + 1;                    dp[i] %= mod;                } else {                    dp[i] = dp[i-1] + dp[i-len_B] + 1;                    dp[i] %= mod;                }            } else {                if (i == 0) {                    dp[0] = 0;                } else {                    dp[i] = dp[i-1];                }            }        }        printf("Case #%d: %d\n", ++Case, (dp[len_A-1]+1) % mod);    }    return 0;}

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <vector>#include <stack>#include <map>#include <cmath>#include <cctype>#include <bitset>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;typedef pair<int, int> Pair;const int mod = 1e9 + 7;const int INF = 0x7fffffff;const int maxn = 1e5 + 10;char A[maxn], B[maxn];bool vis[maxn];int dp[maxn];int Next[maxn];int len_A, len_B;void Build_Next(void);void Match(void);int main(){#ifdef __AiR_H    freopen("in.txt", "r", stdin);#endif // __AiR_H    int T;    scanf("%d", &T);    int Case= 0;    while (T--) {        memset(vis, false, sizeof(vis));        scanf("%s%s", A, B);        len_A = strlen(A), len_B = strlen(B);        Build_Next();        Match();        for (int i = 0; i < len_A; ++i) {            if (vis[i]) {                if (i == 0) {                    dp[i] = 1;                } else if (i < len_B) {                    dp[i] = dp[i-1] + 1;                    dp[i] %= mod;                } else {                    dp[i] = dp[i-1] + dp[i-len_B] + 1;                    dp[i] %= mod;                }            } else {                if (i == 0) {                    dp[0] = 0;                } else {                    dp[i] = dp[i-1];                }            }        }        printf("Case #%d: %d\n", ++Case, (dp[len_A-1]+1) % mod);    }    return 0;}void Build_Next(void){    int i = 0;    int t = Next[0] = -1;    while (i < len_B-1) {        if (t < 0 || B[i] == B[t]) {            ++i;            ++t;            Next[i] = (B[i] != B[t] ? t : Next[t]);        } else {            t = Next[t];        }    }}void Match(void){    int i = 0;    while (1) {        int j = 0;        while (j < len_B && i < len_A) {            if (j < 0 || A[i] == B[j]) {                ++i;                ++j;            } else {                j = Next[j];            }        }        if (i-j < len_A-len_B+1) {            vis[i-j] = true;            i = i-j+1;        } else {            break;        }    }}

0 0