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\n",res);
}

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

posted @ 2018-03-04 21:12  Apocrypha  阅读(237)  评论(0编辑  收藏  举报