zoukankan      html  css  js  c++  java
  • POJ 2346 Lucky tickets(DP,记忆化)

    POJ 2346 Lucky tickets

    题目传送门

    题意:

    定义一个位数为偶数的数为幸运数当且仅当这个数前一半的部分数字之和等于后一半的数字之和,给出一个n,求出有多少个位数小于n的数是幸运数。

    解题过程:

    我们可以比较容易的想到DP,然后我们会发现DP当中我们需要的只是前一半部分或者后一半部分的和不需要具体指导是多少,所以会有很多重复的情况,而如果暴力搜索,那么必然会TLE,所以我们就可以想到记忆化,f[i][j][k]表示枚举到第i位时,前一半部分的和为j,后一半部分的和为k的时候,幸运数字的个数为多少,然后转移的方程就是枚举0~9数字,由(i,j,k)转移到(i+1,j+num,k)或者(i+1,j,k+num)。这样就会避免很多重复的计算了。

    AC代码:

    #pragma GCC optimize (3)
    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    #include <list>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    int n;
    ll f[15][60][60];
    
    ll dfs(int cnt,int ans1,int ans2) {
        if(f[cnt][ans1][ans2]!=-1)return f[cnt][ans1][ans2];
        if(cnt==n*2) {
            if(ans1==ans2)return 1ll;
        else return 0ll;
        }
        ll ans=0;
        for(int i=0;i<=9;i++) {
        if(cnt<n)ans+=dfs(cnt+1,ans1+i,ans2);
        else ans+=dfs(cnt+1,ans1,ans2+i);
        }
        return f[cnt][ans1][ans2]=ans;
    }
    
    int main() {
        scanf("%d",&n);
        n/=2;
        memset(f,-1,sizeof f);
        ll res=dfs(0,0,0);
        printf("%lld
    ",res);
    }

    本人蒟蒻OIer一枚,欢迎加QQ:840776708一起学习蛤。

    「我不敢下苦功琢磨自己,怕终于知道自己并非珠玉;然而心中既存着一丝希冀,便又不肯甘心与瓦砾为伍。」
  • 相关阅读:
    中文转数字
    半角全角互转
    sql快速查记录数
    杀进程批处理
    线程基本用法
    sql游标用法示例
    BUGFREE的使用
    SQL常用函数
    ASP.NET 2.0 下的验证码控件
    经典sql语句
  • 原文地址:https://www.cnblogs.com/Apocrypha/p/9433669.html
Copyright © 2011-2022 走看看