zoukankan      html  css  js  c++  java
  • 【hdu4507】吉哥系列故事——恨7不成妻 数位dp

    题目描述

    求 $[L,R]$ 内满足:数位中不包含7、数位之和不是7的倍数、本身不是7的倍数 的所有数的平方和 mod $10^9+7$ 。

    输入

    输入数据的第一行是case数T(1 <= T <= 50),然后接下来的T行表示T个case;每个case在一行内包含两个正整数L, R(1 <= L <= R <= 10^18)。

    输出

    请计算[L,R]中和7无关的数字的平方和,并将结果对10^9 + 7 求模后输出。

    样例输入

    3
    1 9
    10 11
    17 17

    样例输出

    236
    221
    0


    题解

    数位dp

    由于要求数位之和不是7的倍数,因此要维护数位之和模7的值。

    由于要求本身不是7的倍数,因此要维护本身模7的值。

    所以设 $f[i][j][k][l]$ 表示 $i$ 位数,最高位为 $j$ ,数位之和模7为 $k$ ,本身模7为 $l$ ,且数位中不出现7的......的什么?

    题目所求为平方和,而每个数都加上一个数后,平方和不能直接加。

    考虑到一个公式: $(a+b)^2=a^2+2ab+b^2$ ,因此 $sum(a+v)^2=sum a^2+2vsum a+v^2sum a^0$ ,所以维护0次方和(即个数)、1次方和及2次方和即可实现给每个数加上一个数。

    具体可以使用结构体维护。

    然后就是数位dp的老套路:先处理位数不满的,统计到答案中;然后从高位到低位枚举第几位,该位小于原数的该位则一定满足区间条件,把符合条件的数加到答案中。

    本题中dp时需要记录前面的数位之和、前面的数(加到答案时还需要加上该数),并且当出现7时直接跳出。

    把询问转化为 $[1,n)$的区间更容易一些。

    注意一下 $10^{19}$ 爆long long,因此找位数时还要判断当位数等于19时直接跳出(比竟无法存储 $10^{19}$ )。

    同时还要注意一下取模问题。

    #include <cstdio>
    #define mod 1000000007
    typedef long long ll;
    struct data
    {
    	ll v[3];
    	ll &operator[](ll a) {return v[a];}
    	data() {v[0] = v[1] = v[2] = 0;}
    	data operator+=(data a)
    	{
    		v[0] = (v[0] + a[0]) % mod;
    		v[1] = (v[1] + a[1]) % mod;
    		v[2] = (v[2] + a[2]) % mod;
    		return *this;
    	}
    	data operator+(ll a)
    	{
    		data ans;
    		a %= mod;
    		ans[0] = v[0];
    		ans[1] = (v[1] + a * v[0]) % mod;
    		ans[2] = (v[2] + 2 * a * v[1] + a * a % mod * v[0]) % mod;
    		return ans;
    	}
    }f[19][10][7][7];
    ll b[19];
    void init()
    {
    	int i , j , k , l , m;
    	f[0][0][0][0][0] = b[0] = 1;
    	for(i = 1 ; i < 19 ; i ++ )
    	{
    		b[i] = b[i - 1] * 10;
    		for(j = 0 ; j < 10 ; j ++ )
    			for(k = 0 ; k < 10 ; k ++ )
    				for(l = 0 ; l < 7 ; l ++ )
    					for(m = 0 ; m < 7 ; m ++ )
    						if(j != 7)
    							f[i][j][(l + j) % 7][(m + j * b[i - 1]) % 7] += f[i - 1][k][l][m] + j * b[i - 1];
    	}
    }
    ll calc(ll n)
    {
    	int i , j , k , l , s = 0 , now , di = 1;
    	ll v = 0;
    	data ans;
    	for(i = 1 ; i < 19 && b[i] <= n ; i ++ )
    		for(j = 1 ; j < 10 ; j ++ )
    			for(k = 1 ; k < 7 ; k ++ )
    				for(l = 1 ; l < 7 ; l ++ )
    					ans += f[i][j][k][l];
    	for( ; i ; i -- )
    	{
    		now = n / b[i - 1] % 10;
    		for(j = di ; j < now ; j ++ )
    			for(k = 0 ; k < 7 ; k ++ )
    				for(l = 0 ; l < 7 ; l ++ )
    					if((k + s) % 7 && (l + v) % 7)
    						ans += f[i][j][k][l] + v;
    		if(now == 7) break;
    		s = (s + now) % 7 , v += now * b[i - 1] , di = 0;
    	}
    	return ans[2];
    }
    int main()
    {
    	init();
    	int T;
    	ll n , m;
    	scanf("%d" , &T);
    	while(T -- ) scanf("%lld%lld" , &n , &m) , printf("%lld
    " , (calc(m + 1) - calc(n) + mod) % mod);
    	return 0;
    }
    
  • 相关阅读:
    __all__
    python内置函数
    qZnF新存马王至许观制两利各
    PHP中获取当前页面的完整URL
    DedeCms用tag调用全站相关文章
    dedecms如何利用tag来调取相关文章
    SQL Server TempDB
    SQL Server Pivot 隐藏group
    Rebind and Rewind in Execution Plans
    batch 数字进制的问题
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7813613.html
Copyright © 2011-2022 走看看