zoukankan      html  css  js  c++  java
  • hdu 4734 数位dp

    题意:For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).(懒得翻译了哈哈哈)

    题解:由于这里要比较的是每个数位的带权和,我们定义dp[i][j]为从i开始枚举,和为j的时候有多少满足题目意思的解

    代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    using namespace std;
    int a[20];
    int dp[15][5100];
    int len;
    int getsum(int x)
    {
        int tsum=0;
        int f=1;
        while(x)
        {
            tsum+=(x%10)*f;
            f*=2;
            x/=10;
        }
        return tsum;
    }
    int dfs(int pos,int sta,int key,bool limit)
    {
        if(pos==-1) return 1;
        if(!limit && dp[pos][sta]!=-1 ) return dp[pos][sta];
        int up=limit ? a[pos] : 9;
        int sum=0;
       // cout<<pos<<" "<<up<<endl;
    
        for(int i=0;i<=up;i++)
        {
            int temp=sta+i*pow(2,pos);
           // cout<<temp<<endl;
            if(temp <= key)
            {
                sum+=dfs(pos-1,temp,key,limit & i==a[pos]);
            }
        }
        if(!limit) dp[pos][sta]=sum;
      //  cout<<"pos: "<<pos<<" "<<"sta :"<<sta<<" "<<"sum :"<<sum<<endl;
        return sum;
    }
    int solve(int tempa,int b)
    {
        int akey=getsum(tempa);
      //  cout<<akey<<endl;
        int pos=0;
        while(b)
        {
            a[pos++]=b%10;
            b/=10;
        }
        len=pos-1;
        return dfs(len,0,akey,true);
    }
    
    int main()
    {
       int t,Case=0;
       cin>>t;
       while(t--)
       {
           memset(dp,-1,sizeof(dp));
           int aa,b;
           cin>>aa>>b;
           printf("Case #%d: %d
    ",++Case,solve(aa,b));
       }
        return 0;
    }

    但是,这个会TLE,没错,会TLE.....

    仔细看一下,每次我们都要初始话dp数组,代价有点大,但是按我们刚才的思路来的话,必须每次求的时候都初始话一次

    换个思路,dp[i][j]表示枚举到i这个位置的时候,还需要j才能满足条件,这个时候dp数组就和输入的数无关了(em..建议多理理这个不会太好理解)

    AC代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    using namespace std;
    int a[20];
    int dp[15][5100];
    int len;
    int getsum(int x)
    {
        int tsum=0;
        int f=1;
        while(x)
        {
            tsum+=(x%10)*f;
            f*=2;
            x/=10;
        }
        return tsum;
    }
    int dfs(int pos,int sta,bool limit)// 还需要sta
    {
        if(pos==-1) return sta>=0;
        if(sta < 0) return 0;
        if(!limit && dp[pos][sta]!=-1 ) return dp[pos][sta];
        int up=limit ? a[pos] : 9;
        int sum=0;
        for(int i=0;i<=up;i++)
        {
            int temp=sta-i*(1<<pos);
           // cout<<temp<<endl;
            sum+=dfs(pos-1,temp,limit & i==a[pos]);
        }
        if(!limit) dp[pos][sta]=sum;
      //  cout<<"pos: "<<pos<<" "<<"sta :"<<sta<<" "<<"sum :"<<sum<<endl;
        return sum;
    }
    int solve(int tempa,int b)
    {
        int akey=getsum(tempa);
        int pos=0;
        while(b)
        {
            a[pos++]=b%10;
            b/=10;
        }
        len=pos-1;
        return dfs(len,akey,true);
    }
    
    int main()
    {
       int t,Case=0;
       scanf("%d",&t);
       memset(dp,-1,sizeof(dp));
       while(t--)
       {
          //
           int aa,b;
           scanf("%d %d",&aa,&b);
           printf("Case #%d: %d
    ",++Case,solve(aa,b));
       }
        return 0;
    }
  • 相关阅读:
    多线程下单例模式:懒加载(延迟加载)和即时加载
    Java 线程同步
    java 多线程之wait(),notify,notifyAll(),yield()
    序列化和反序列化及线程实现方式
    错题解析
    错题解析
    考试:错题总结
    测试:错题总结
    hashCode与equals的区别与联系
    @Not
  • 原文地址:https://www.cnblogs.com/z1141000271/p/8408616.html
Copyright © 2011-2022 走看看