• zoj4100 Balanced Number 数位DP


    题目的意思是询问[A,B]区间内,有多少个Balanced Number,每个Balanced Number符合以下条件:

    将一个数按位拆分,存在一个位置mid,使得sigma(val[i]*(mid-i))=sigma(val[j]*(j-mid)) {i<mid,j>mid}

    然后就是一脸数位dp的样子...

    一开始的想法是枚举mid,因为分析了一下,除0以为的某个Balanced Number,一定只有一个位置符合条件。

    然后接下来就脑残了,将数字拆成两半来dp,然后合并的时候死活合并不了。后来想了一下,瞬间觉得自己脑残了,根本就不用拆分。直接从后往前dp就行,没想好代码怎么写,就开始敲,真的很忧伤..

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<map>
    #include<queue>
    #include<iostream>
    
    using namespace std;
    
    #define For(i,forN) for(int i=0;i<forN;i++)
    #define sf  scanf
    #define pf  printf
    #define mp  make_pair
    
    #define _clr(x,y)   memset(x,(y),sizeof(x))
    
    typedef long long LL;
    
    const int Maxn=21,Maxl=1400,Maxe=Maxl;
    LL dp[2][Maxn][Maxl];
    int num[Maxn],len;
    
    typedef long long LL;
    LL A,B;
    
    LL getAns(int mid)
    {
        _clr(dp,0);
        dp[0][len][0]=1;//0表示x<=val,1表示x>val
        for(int i=len-1;i>=0;i--)
        {
            int s=0,l=i-mid;
            for(int j=0;j<Maxe;j++)
            {
                for(int k=s;k<10;k++)
                {
                    int tj=l*k+j;
                    if(tj<Maxe && tj>=0)
                    {
                        if(k<num[i])//那么x一定小于val
                        {
                            dp[0][i][tj]+=dp[0][i+1][j]+dp[1][i+1][j];
                        }
                        else if(k>num[i])//那么x一定大于val
                        {
                            dp[1][i][tj]+=dp[0][i+1][j]+dp[1][i+1][j];
                        }
                        else
                        {
                            dp[0][i][tj]+=dp[0][i+1][j];
                            dp[1][i][tj]+=dp[1][i+1][j];
                        }
                    }
    
                }
            }
        }
        return dp[0][0][0];
    }
    
    LL cal(LL val)
    {
        if(val<0)   return 0;
        if(val<10)  return val+1;
        len=0;
        while(val)
        {
            num[len++]=val%10;
            val/=10;
        }
        reverse(num,num+len);
        LL ans=0;
        for(int i=0;i<len;i++)
        ans+=getAns(i);
        return ans-len+1;
    }
    
    int main()
    {
        int cas;
        cin>>cas;
        while(cas--)
        {
            cin>>A>>B;
            cout<<cal(B)-cal(A-1)<<endl;
        }
    }
  • 相关阅读:
    Activity跳转动画
    如何查询自己的手机版本?欧版、亚太、港行、还是国行?
    VC程序员常用工具汇总
    陈灯可重用代码段管理器VS插件版5.0发布(代码段收集器、个人代码库、代码片段管理、代码管理)
    基于OSLC的系统集成
    安桌点菜源代码
    eclipse jsp 文字设置
    ubuntu 下 netbeans平台 使用C连接mysql
    使用gdi+实时绘制picturebox(画个叉)
    思路上的转变,运用投影和一阶导数的思想
  • 原文地址:https://www.cnblogs.com/CooCoo/p/3409171.html
Copyright © 2020-2023  润新知