zoukankan      html  css  js  c++  java
  • 基础dp

      队友的建议,让我去学一学kuangbin的基础dp,在这里小小的整理总结一下吧。

      首先我感觉自己还远远不够称为一个dp选手,一是这些题目还远不够,二是定义状态的经验不足。不过这些题目让我在一定程度上加深了对dp的理解,但要想搞好dp,还需要多多练习啊。

      HDU - 1024 开场高能

      给出一个数列,分成m段,求这m段的和的最大值,dp[i][j]表示遍历到第i个数,已经划分了j段,对于每一个数有两种决策,加入上一个区间段,自己成为一个区间段,故dp[i][j] = max(dp[i-1][j]+a[i],dp[k][j-1]+a[i])     1<=k<=i-1,二维数组肯定不能开,所以使用两个数组,另一个数组保存上一次的状态,这样也可以及时的获得第二种情况的答案,然后再更新一遍旧状态就可以。一开始因为初始化问题错了几次。

      

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    using namespace std;
    const int N = 1e6+6;
    const int INF = 1e9;
    #define LL long long
    LL dp1[N],dp2[N];
    LL a[N];
    int main() {
        int n,m;
        while(~scanf("%d%d",&m,&n)) {
            for(int i=1; i <=n; i++) {
                scanf("%lld",&a[i]);
                dp1[i] = dp2[i] = 0;
            }
            dp1[0] = 0;
            dp2[0] = 0;
            for(int i =1; i <= m; i++) {
                LL Max = -INF;
                for(int j=i; j <= n; j++) {
                    Max = max(Max,dp2[j-1]);
                    dp1[j] = max(dp1[j-1]+a[j],Max+a[j]);
                }
                for(int j =i; j <= n; j++) {
                    dp2[j] = dp1[j];
                }
            }
            LL ans = -INF;
            for(int i = m; i <= n; i++) {
                ans = max(ans,dp1[i]);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

      HDU - 1029 感觉跟dp没啥关系

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 1e6+6;
    #define LL long long
    LL a[N];
    int main(){
        int n;
        while(~scanf("%d",&n)){
            for(int i = 0;i < n;i++){
                scanf("%lld",&a[i]);
            }
            sort(a,a+n);
            printf("%lld
    ",a[n/2]);
        }
        return 0;
    }
    View Code

      HDU - 1069 线性dp,排序后求最大权值

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    struct Rec{
        int c,k,g;
    }r[100];
    void setRec(int id,int x,int y,int z){
        r[id].c = x;
        r[id].k = y;
        r[id].g = z;
    }
    int dp[100];
    bool ok(int i,int j){
        if(r[i].c<r[j].c && r[i].k<r[j].k) return true;
        if(r[i].c<r[j].k && r[i].k<r[j].c) return true;
        return false;
    }
    bool cmp(Rec a,Rec b){
        return (a.c*a.k > b.c*b.k);
    }
    int main()
    {
        int n,x,y,z,ca=0;
        while(~scanf("%d",&n)){
            if(!n) break;
            for(int i = 1;i <= 3*n;i += 3){
                scanf("%d%d%d",&x,&y,&z);
                setRec(i,x,y,z);
                setRec(i+1,x,z,y);
                setRec(i+2,y,z,x);
            }
            n = n*3;
            sort(r+1,r+n+1,cmp);
            for(int i=1;i <= n;i++){
    //            cout<<r[i].c<<" "<<r[i].k<<" "<<r[i].g<<endl;
                dp[i] = r[i].g;
                for(int j = 1;j < i;j++){
                    if(ok(i,j)){
                        dp[i] = max(dp[i],dp[j]+r[i].g);
                    }
                }
            }
            int ans = 0;
            for(int i = 1;i <= n;i++){
                ans = max(ans,dp[i]);
            }
            printf("Case %d: maximum height = %d
    ",++ca,ans);
        }
    }
    View Code

      HDU - 1074  之前就做过,但基础dp里居然有状态压缩,因为这里只是求做作业的顺序,从小到大枚举所有状态,对于每一个状态,添加一个作业递推出新的状态,如果一个状态可以由多个途径达到,选择一个最优的,当所有作业选完以后就是答案,回溯状态输出一下就可以。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define N 15
    #define M (1<<N)+N
    const int INF = 1e9;
    struct DP {
        int day,red,fa;
    } dp[M];
    struct Course {
        string name;
        int dl,cost;
    } c[N];
    void outPut(int k,int n) {
        int f = dp[k].fa;
        if(f == -1) return;
        outPut(f,n);
        for(int i =0; i < n; i++) {
            if((k&(1<<i))!=0 && (f&(1<<i))==0) {
                cout<<c[i].name<<endl;
                break;
            }
        }
    }
    int main() {
        int T,n,day;
        scanf("%d",&T);
        while(T--) {
            scanf("%d",&n);
            for(int i = 0; i < n; i++) {
                cin>>c[i].name>>c[i].dl>>c[i].cost;
            }
            int up = (1<<n);
            for(int i = 0; i < up; i++) {
                dp[i].fa = -1;
            }
            dp[0].day = dp[0].red = 0;
            for(int i=0; i < up; i++) {
                for(int j=0; j<n; j++) {
                    if((i&(1<<j)) == 0) {
                        int k = (i|(1<<j));
                        int nday = dp[i].day+c[j].cost;
                        dp[k].day = nday;
                        int nred = max(0,nday-c[j].dl);
                        if(dp[k].fa == -1) {
                            dp[k].red = dp[i].red+nred;
                            dp[k].fa = i;
                        } else if(dp[k].red > dp[i].red+nred) {
                            dp[k].red = dp[i].red+nred;
                            dp[k].fa = i;
                        }
                    }
                }
            }
            printf("%d
    ",dp[up-1].red);
            outPut(up-1,n);
        }
        return 0;
    }
    View Code

      HDU - 1087 最长递增子序列

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define LL long long
    #define N 1005
    const int INF = 1e9;
    LL dp[N],a[N];
    int main()
    {
        int n;
        while(~scanf("%d",&n)){
            if(!n) break;
            LL ans = -INF;
            for(int i = 0;i < n;i++){
                scanf("%lld",&a[i]);
                dp[i] = a[i];
                for(int j = 0;j < i;j++){
                    if(a[i]>a[j]) dp[i] = max(dp[i],dp[j]+a[i]);
                }
                ans = max(ans,dp[i]);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

      HDU - 1114 完全背包,恰好装满,一开始初始化-1为不可达状态,状态转移的时候判断一下不可达状态就可以

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 10005;
    const int M = 505;
    int dp[N];
    struct Thing{
        int p,w;
    }t[M];
    int main()
    {
        int T,E,F,n;
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&E,&F);
            int all = F-E;
            scanf("%d",&n);
            for(int i = 0;i <n;i++){
                scanf("%d %d",&t[i].p,&t[i].w);
            }
            memset(dp,-1,sizeof(dp));
            dp[0] = 0;
            for(int i = 0;i < n;i++){
                for(int j =t[i].w; j<= all;j++){
                    int Last = j-t[i].w;
                    if(dp[Last] == -1) continue;
                    if(dp[j]==-1) dp[j] = dp[Last]+t[i].p;
                    else dp[j] = min(dp[j],dp[Last]+t[i].p);
                }
            }
            if(dp[all] == -1){
                printf("This is impossible.
    ");
            }else printf("The minimum amount of money in the piggy-bank is %d.
    ",dp[all]);
        }
        return 0;
    }
    View Code

      HDU - 1176 数塔,倒着算

      

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define N 100005
    int dp[11][N],a[11][N];
    int main()
    {
        int n,t,x,Mt;
        while(~scanf("%d",&n)){
            if(!n) break;
            memset(a,0,sizeof(a));
            Mt = 0;
            for(int i=0;i<n;i++){
                scanf("%d%d",&x,&t);
                a[x][t]++;
                Mt = max(Mt,t);
            }
            for(int i=0;i<=10;i++){
                dp[i][Mt+1] = 0;
            }
            for(int i=Mt;i>=0;i--){
                for(int j=0;j <= 10;j++){
                    int Max = -1;
                    if(j==0) Max = max(dp[j][i+1],dp[j+1][i+1]);
                    else if(j==10) Max = max(dp[j][i+1],dp[j-1][i+1]);
                    else Max = max(max(dp[j][i+1],dp[j+1][i+1]),dp[j-1][i+1]);
                    dp[j][i] = Max + a[j][i];
                }
            }
            printf("%d
    ",dp[5][0]);
        }
        return 0;
    }
    View Code

      HDU - 1260  基础dp,12点的时候算am,还是pm呢。。题目中都没有这组样例,我还困惑了一会

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define N 2005
    int a[N],b[N],dp[N];
    int main() {
        int T,n;
        scanf("%d",&T);
        while(T--) {
            scanf("%d",&n);
            for(int i=1; i<=n; i++) {
                scanf("%d",&a[i]);
            }
            for(int i=2; i<=n; i++) {
                scanf("%d",&b[i]);
            }
            dp[0] = 0;
            for(int i=1; i<=n; i++) {
                if(i==1) dp[i] = a[i];
                else dp[i] = min(dp[i-1]+a[i],dp[i-2]+b[i]);
            }
            int tmp = dp[n];
            int s = tmp%60;
            tmp /= 60;
            int m = tmp%60;
            tmp /= 60;
            int h = tmp%60+8;
            h %= 24;
            bool f = true;
            if(h == 12) f = false;
            if(h > 12) {
                h -= 12;
            }
            printf("%02d:%02d:%02d ",h,m,s);
            if(f) printf("am
    ");
            else printf("pm
    ");
        }
        return 0;
    }
    View Code

      HDU - 1257  这个题目是有争议的,但是我认为这个题目就是让求,将此序列划分为最长递减序列的最少条数,dp[i]代表第i个子序列的最小值,一个数的决策,当然是加入到距离dp[i]最小的那一个,这样能保证条数最少,而这样做正好就对应了kuangbin的贪心代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 1e6;
    const int INF = 1e9;
    int dp[N]; ///dp[i]表示第i个子序列的最小值
    int main()
    {
        int n,m,tmp;
        while(~scanf("%d",&n)){
            m = 0;
            for(int i=0;i<n;i++){
                scanf("%d",&tmp);
                int Min = INF,End=-1;
                for(int j =0;j < m;j++){
                    if(tmp<=dp[j] && dp[j]-tmp < Min){
                        Min = min(Min,dp[j]-tmp);
                        End = j;
                    }
                }
                if(End == -1) dp[m++] = tmp;
                else dp[End] = tmp;
            }
            printf("%d
    ",m);
        }
        return 0;
    }
    View Code

      HDU - 1160

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 1005;
    const int INF = 1e9;
    struct DP{
        int len,pre;
    }dp[N];
    struct Mice{
        int w,s,id;
    }m[N];
    bool cmp(Mice a,Mice b){
        if(a.w != b.w) return a.w < b.w;
        else return a.s < b.s;
    }
    int Stack[N];
    int main()
    {
    //    freopen("in.cpp","r",stdin);
        int tot=0;
        while(scanf("%d %d",&m[tot].w,&m[tot].s) != EOF){
                m[tot].id = tot;
                tot++;
        }
        sort(m,m+tot,cmp);
        for(int i =0;i < tot;i++){
            dp[i].len = 1;
            dp[i].pre = -1;
            for(int j=0;j<i;j++){
                if(m[i].w>m[j].w && m[i].s<m[j].s){
                    if(dp[i].len < dp[j].len+1){
                        dp[i].len = dp[j].len+1;
                        dp[i].pre = j;
                    }
                }
            }
        }
        int Max = -INF,End=-1;
        for(int i=0;i<tot;i++){
            if(dp[i].len > Max){
                Max = dp[i].len;
                End = i;
            }
        }
        printf("%d
    ",Max);
        int top=0;
        while(End != -1){
            Stack[top++] = m[End].id+1;
            End = dp[End].pre;
        }
        while(top != 0){
            printf("%d
    ",Stack[--top]);
        }
        return 0;
    }
    View Code

      POJ - 1015 这里面我感觉这个题是很难的了,因为我没有找到状态的正确定义,原来是dp[i][k]代表已经选出i个人,差为k的最大和,使用path记录每个状态的决策,在选人的时候通过回溯判断这个人是否已经被选过,我一开始用的vis,各种wa,还没有明白是怎么回事,一开始平移区间还移出了毛病。。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 205;
    const int INF = 1e9;
    int dp[22][808],path[22][808];
    int cha[N],he[N],x[N],y[N],n,m;
    ///使用path记录此状态选的是哪一个人
    bool ok(int i,int j,int k) {
        while(i>0 && path[i][j] != -1) {
            if(path[i][j] == k) return false;
            j -= cha[path[i][j]];
            i--;
        }
        return true;
    }
    int out[N],os,p,d;
    void Print(int i,int j) {
        os = p = d = 0;
        while(i>0 && path[i][j] != -1) {
            int k = path[i][j];
            j -= cha[k];
            i--;
            out[os++] = k;
            p += x[k];
            d += y[k];
        }
    }
    int main() {
        int ca=0;
        while(~scanf("%d%d",&n,&m)) {
            if(n==0 && m==0) break;
            for(int i = 1; i <= n; i++) {
                scanf("%d%d",&x[i],&y[i]);
                cha[i] = x[i]-y[i];
                he[i] = y[i]+x[i];
            }
            memset(dp,-1,sizeof(dp));
            memset(path,-1,sizeof(path));
            int km = m*20;
            dp[0][km] = 0;
            for(int i=0; i<m; i++) {
                for(int j=0; j<=2*km; j++) {
                    if(dp[i][j] == -1) continue;
                    for(int k=1; k<=n; k++) {
                        int nj = j+cha[k];
                        if(!ok(i,j,k)) continue;
                        if(dp[i+1][nj]<dp[i][j]+he[k]) {
                            dp[i+1][nj] = dp[i][j] + he[k];
                            path[i+1][nj] = k;
                        }
                    }
                }
            }
            int Min = INF,End=-1,Max = -INF;
            for(int i = 0; i <= 2*km; i++) {
                if(dp[m][i]!=-1) {
                    if(abs(i-km)<Min) {
                        Min = abs(i-km);
                        End = i;
                        Max = dp[m][i];
                    } else if(abs(i-km) == Min&&dp[m][i]>Max) {
                        End = i;
                        Max = dp[m][i];
                    }
                }
            }
            printf("Jury #%d
    ",++ca);
            Print(m,End);
            printf("Best jury has value %d for prosecution and value %d for defence:
    ",p,d);
            sort(out,out+os);
            for(int i = 0; i < os; i++) {
                printf(" %d",out[i]);
            }
            printf("
    
    ");
        }
        return 0;
    }
    View Code

      POJ - 1458 最长公共子串

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 1e3 + 3;
    const int INF = 1e9;
    char a[N],b[N];
    int dp[N][N];
    int main()
    {
        while(~scanf("%s%s",a+1,b+1)){
            int lena = strlen(a+1);
            int lenb = strlen(b+1);
            memset(dp,0,sizeof(dp));
            for(int i = 0;i <= lena;i++){
                for(int j=0;j <= lenb;j++){
                    if(i==0||j==0) dp[i][j] = 0;
                    else{
                        if(a[i]==b[j]) dp[i][j] = dp[i-1][j-1]+1;
                        dp[i][j]=max(dp[i][j],max(dp[i-1][j],dp[i][j-1]));
                    }
                }
            }
            printf("%d
    ",dp[lena][lenb]);
        }
        return 0;
    }
    View Code

      POJ - 1661 它只能从板的两边下落这是最重要的,dp[i][2]代表从第i个板子的左边或者右边掉到地上所需的最少时间,然后这就变成了线性dp,正常转移即可,然后有几个小坑,比如有可能直接落到地上,一开始忘记考虑这个wa了一发

      POJ - 2533 最长递增子序列

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 1e3 + 3;
    const int INF = 1e9;
    int dp[N],a[N];
    int main()
    {
        int n,ans;
        while(~scanf("%d",&n)){
            ans = -INF;
            for(int i = 0;i < n;i++){
                scanf("%d",&a[i]);
                dp[i] = 1;
                for(int j=0;j<i;j++){
                    if(a[i]>a[j]){
                        dp[i] = max(dp[i],dp[j]+1);
                    }
                }
                ans = max(ans,dp[i]);
            }
            printf("%d
    ",ans);
        }
    }
    View Code

      POJ - 3186  因为只能从最上面和最下面选数,所以可以定义状态,dp[i][j]表示从i到j还没有被选出所能到达的最大值

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 2e3 + 3;
    const int INF = 1e9;
    int dp[N][N],a[N];
    int main()
    {
        int n;
        while(~scanf("%d",&n)){
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
            }
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++){
                for(int j=n;j>=i;j--){
                    int nd = n-(j-i+1);
                    if(i==1 && j==n) continue;
                    if(j!=n) dp[i][j]=max(dp[i][j],dp[i][j+1]+a[j+1]*nd);
                    if(i!=1) dp[i][j]=max(dp[i][j],dp[i-1][j]+a[i-1]*nd);
                }
            }
            int ans = -INF;
            for(int i=1;i<=n;i++){
                ans = max(ans,dp[i][i]+a[i]*n);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

      HDU - 1078 记忆化搜索,一开始读错了题,以为k步可以拐弯,想复杂了

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N = 105;
    const int INF = 1e9;
    int dp[N][N],n,k;
    int mp[N][N],go[4][2]= {1,0,-1,0,0,-1,0,1};
    bool inMap(int x,int y) {
        return (x>=0&&x<n&&y>=0&&y<n);
    }
    int dfs(int x,int y) {
        if(dp[x][y] != -1) return dp[x][y];
        int Max = 0,nx,ny;
        for(int j =1; j<=k; j++) {
            for(int i = 0; i < 4; i++) {
                nx = x + go[i][0]*j;
                ny = y + go[i][1]*j;
                if(inMap(nx,ny) && mp[nx][ny] > mp[x][y]) {
                    Max = max(Max,dfs(nx,ny));
                }
            }
        }
        return dp[x][y] = mp[x][y] + Max;
    }
    int main() {
        while(~scanf("%d%d",&n,&k)) {
            if(n==-1 && k==-1) break;
            for(int i=0; i<n; i++) {
                for(int j=0; j<n; j++) {
                    scanf("%d",&mp[i][j]);
                }
            }
            memset(dp,-1,sizeof(dp));
            int ans = dfs(0,0);
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

      HDU - 2859 挺巧妙的题,沿着对角线扩展,dp[i][j]表示以(i,j)位置为右上角所能形成的最大对称矩阵,转移状态的时候需要注意,dp[i-1][j+1]如果大于上一个状态,直接由上一个状态加1,如果小于等于上一个状态,那么就等于延伸的最大长度,他的正确性由前一个状态保证

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N = 1005;
    const int INF = 1e9;
    char mp[N][N];
    int dp[N][N];
    int main()
    {
        int n,ans;
        while(~scanf("%d",&n)){
            if(n==0) break;
            for(int i=1;i<=n;i++){
                scanf("%s",mp[i]+1);
            }
            for(int i=1;i<=n;i++){
                dp[i][1] = dp[n][i] = 1;
            }
            ans = 1;
            for(int i=n-1;i>=1;i--){
                for(int j=2;j<=n;j++){
                    int len = 0;
                    while(j-len>=1&&i+len<=n && mp[i+len][j]==mp[i][j-len]){
                        len++;
                    }
    //                cout<<mp[i][j]<<"   len = "<<len<<endl;
                    if(len >= dp[i+1][j-1]+1) {
                        dp[i][j] = dp[i+1][j-1]+1;
                    }else dp[i][j] = len;
                    ans = max(ans,dp[i][j]);
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

      POJ - 3616 被这个题晃了一下,本来就是个线性dp,跟n没关系

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N = 1e3+3;
    const int INF = 1e9;
    int dp[N];
    struct Thing{
        int l,r,w;
    }t[N];
    bool cmp(Thing a,Thing b){
        if(a.l != b.l) return a.l < b.l;
        return a.r < b.r;
    }
    int main()
    {
        int n,m,r,ans;
        while(~scanf("%d%d%d",&n,&m,&r)){
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&t[i].l,&t[i].r,&t[i].w);
            }
            ans = -INF;
            sort(t+1,t+1+m,cmp);
            for(int i=1;i<=m;i++){
                dp[i] = t[i].w;
                for(int j=1;j < i;j++){
                    if(t[i].l >= t[j].r+r){
                        dp[i] = max(dp[i],dp[j]+t[i].w);
                    }
                }
                ans = max(ans,dp[i]);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

      POJ - 3666 将一个序列修改为有序序列的最小花费,对于一个长度为n的序列,如果将他改成非递减的序列,那么可以证明最后一个数可以是这个序列的最大值,而不影响答案,对n+1的序列也是如此,归纳知最终序列中的数可以全部来自原先序列,定义dp[i][j]为选到第i个数,最后一个数为有序序列的第j个数的最小值,滚动数组,枚举上一个状态的结尾数,之所以要排序是因为要保证这个序列的有序性,正序倒序分别求一次就可以得到最优解。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N = 2005;
    const int INF = 1e9;
    int a[N],dp[N],n,b[N];
    int fun1(){
        sort(b+1,b+1+n);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            int Min = INF;
            for(int j=1;j<=n;j++){
                Min = min(Min,dp[j]);
                dp[j] = Min+abs(a[i]-b[j]);
            }
        }
        int res = INF;
        for(int i=1;i<=n;i++){
            res = min(res,dp[i]);
        }
        return res;
    }
    bool cmp(int a,int b){
        return a > b;
    }
    int fun2(){
        sort(b+1,b+1+n,cmp);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            int Min = INF;
            for(int j=1;j<=n;j++){
                Min = min(Min,dp[j]);
                dp[j] = Min+abs(a[i]-b[j]);
            }
        }
        int res = INF;
        for(int i=1;i<=n;i++){
            res = min(res,dp[i]);
        }
        return res;
    }
    int main() {
        int ans;
        while(~scanf("%d",&n)) {
            for(int i=1; i<=n; i++) {
                scanf("%d",&a[i]);
                b[i] = a[i];
            }
            ans = min(fun1(),fun2());
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

      

  • 相关阅读:
    BZOJ.3884.上帝与集合的正确用法(扩展欧拉定理)
    HDU.5608.function(杜教筛)
    HDU.5628.Clarke and math(狄利克雷卷积 快速幂)
    51Nod.1244.莫比乌斯函数之和(杜教筛)
    SPOJ.Visible Lattice Points(莫比乌斯反演)
    BZOJ.2301.[HAOI2011]Problem B(莫比乌斯反演 容斥)
    BZOJ.2242.[SDOI2011]计算器(扩展欧几里得 BSGS)
    Codeforces757E.Bash Plays With Functions(积性函数 DP)
    插值法
    2、Windows下安装配置Redis
  • 原文地址:https://www.cnblogs.com/jifahu/p/6284317.html
Copyright © 2011-2022 走看看