zoukankan      html  css  js  c++  java
  • 【hdu4734】F(x) 数位dp

    题目描述

    对于一个非负整数 $x=​​overline{a_na_{n-1}...a_2a_1}$ ,设 $F(x)=a_n·2^{n-1}+a_{n-1}·2^{n-2}+...+a_2·2^1+a_1·2^0=sumlimits_{i=1}^na_i·2^{i-1}$ 

    多次询问 $[0,B]$ 区间内 $F$ 值小于等于 $F(A)$ 的数的个数。

    输入

    The first line has a number T (T <= 10000) , indicating the number of test cases.
    For each test case, there are two numbers A and B (0 <= A,B < 109)

    输出

    For every case,you should output "Case #t: " at first, without quotes. The t is the case number starting from 1. Then output the answer.

    样例输入

    3
    0 100
    1 10
    5 100

    样例输出

    Case #1: 1
    Case #2: 2
    Case #3: 13


    题解

    数位dp

    考虑到最大的 $F(x)=F(999999999)=9207$ ,因此可以设 $f[i][j][k]$ 表示 $i$ 位数,最高位为 $j$ ,$F$函数的值为 $k$ 的数的个数。

    首先预处理出 $f$ 数组,考虑当前位的贡献来计算。

    然后先计算出$F(a)$,然后要求的就是$[0,b+1)$内 $F$值小于等于 $F(a)$ 的数的个数。

    按照常规的数位dp思路,先考虑不足总位数的,然后再从高位向低位枚举,考虑以前位的贡献,得出当前的范围,直接计算即可。

    由于有多组询问,需要使用前缀和优化转移过程。

    这里为了不开long long把询问区间转化为 $[0,b)$ (实际上是 $[1,b)$),因此需要计算 $b$ 对答案的贡献。

    #include <cstdio>
    int f[10][10][10010] , b[10];
    void init()
    {
    	int i , j , k , l;
    	f[0][0][0] = b[0] = 1;
    	for(i = 1 ; i < 10 ; i ++ )
    	{
    		b[i] = b[i - 1] * 10;
    		for(j = 0 ; j < 10 ; j ++ )
    			for(k = 0 ; k < 10 ; k ++ )
    				for(l = j << (i - 1) ; l <= 10000 ; l ++ )
    					f[i][j][l] += f[i - 1][k][l - (j << (i - 1))];
    	}
    	for(i = 1 ; i < 10 ; i ++ )
    		for(j = 0 ; j < 10 ; j ++ )
    			for(k = 1 ; k <= 10000 ; k ++ )
    				f[i][j][k] += f[i][j][k - 1];
    }
    int calc(int n)
    {
    	int t = 1 , ans = 0;
    	while(n) ans += n % 10 * t , n /= 10 , t <<= 1;
    	return ans;
    }
    int query(int n , int m)
    {
    	int i , j , p , di = 1 , ans = 1 + (calc(n) <= m);
    	for(i = 1 ; b[i] <= n ; i ++ )
    		for(j = 1 ; j < 10 ; j ++ )
    			ans += f[i][j][m];
    	for( ; i ; i -- )
    	{
    		p = n / b[i - 1] % 10;
    		for(j = di ; j < p ; j ++ ) ans += f[i][j][m];
    		m -= p << (i - 1) , di = 0;
    		if(m < 0) break;
    	}
    	return ans;
    }
    int main()
    {
    	init();
    	int T , i , a , b;
    	scanf("%d" , &T);
    	for(i = 1 ; i <= T ; i ++ ) scanf("%d%d" , &a , &b) , printf("Case #%d: %d
    " , i , query(b , calc(a)));
    	return 0;
    }
    
  • 相关阅读:
    汽车发动机参数指标含义
    谷歌浏览器Google Chrome和Adobe Flash Plugins插件安装问题
    今天研究成功ASP动态管理数据表及字段
    漂亮的弹出对话框!
    Opera Dragonfly 提供下载了
    javascript客户端验证函数大全
    C# Regex类用法
    只能输入数字的TextBox
    c#,winform,treeview,选中节点,选中相应的全部子节点,取消节点,取消父节点,小技巧
    WinForm中如何判断关闭事件来源于用户点击右上角的“关闭”按钮
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7813478.html
Copyright © 2011-2022 走看看