hdu 4507 吉哥系列故事——恨7不成妻 [按位dp]
zzy 2013.3.22@科A232
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4507
题目描述:求一个区间[L, R]中和7无关的数的平方和,和7无关的数定义为同时不满足下面三点:
1.各位数字不包含7;
2.各位数字之和不是7的倍数;
3.这个整数不是7的倍数。
解题思路:典型的按位dp。一开始想会不会是数学结论题,但是很快觉得数学一点不靠谱,然后发现按位dp可做。
我的做法是求出区间[0, N]中满足条件的数的平方和,这样可以不用卡下界。
定义数组dp[ d ][ u ][ i ][ j ],d表示dp到第d位,u表示是否卡上界(按惯例,0表示卡上界),i表示前缀的各位数字和模7为i,j表示前缀表示的整数模7为j。每个元素存num、sum、ssum三个值。num表示满足条件的前缀数量,sum则是这些前缀表示的整数的和,ssum是这些前缀表示的整数的平方和。
dp从最高位到最低位枚举p,再枚举当前位的数字d,并枚举上一位p+1位的dp数组最后两维i:0~6,j:0~6。计算出转移到p位时的余数值:
ii = (i + d)%7 jj = (j * 10 + d)%7
最基本的转移方程是:
dp[ p ][ 1 ][ ii ][ jj ].num += dp[ p + 1][ 1 ][ i ][ j ];
dp[ p ][ 1 ][ ii ][ jj ].sum += dp[ p + 1 ][ 1 ][ i ][ j ].sum * 10
+ dp[ p + 1 ][ 1 ][ i ][ j ].num * d;
dp[ p ][ 1 ][ ii ][ jj ].ssum += dp[ p + 1 ][ 1 ][ i ][ j ].ssum * 100
+ dp[ p + 1 ][ 1 ][ i ][ j ].sum * 20 * d
+ d * d * dp[ p + 1 ][ 1 ][ i ][ j ].num;
再注意考虑哈上界问题就行了。
源代码:
1 //zzy.2013.3.21AC 2 #include<cstdio> 3 #include<iostream> 4 #include<algorithm> 5 6 using namespace std; 7 8 #define ll long long 9 #define MOD (1000000007LL) 10 11 typedef struct 12 { 13 ll num,sum,ssum; 14 }node; 15 16 ll digits[21]; 17 node dp[21][2][7][7]; 18 19 void ini(ll len) 20 { 21 for(ll i = 1; i <= len + 1; ++i){ 22 for(ll j = 0; j < 2; ++j){ 23 for(ll k = 0; k < 7; ++k){ 24 for(ll m = 0; m < 7; ++m){ 25 dp[i][j][k][m].num = 0; 26 dp[i][j][k][m].sum = 0; 27 dp[i][j][k][m].ssum = 0; 28 } 29 } 30 } 31 } 32 } 33 34 ll Len(ll N) 35 { 36 ll ret = 0; 37 while(N){ 38 ret ++; 39 digits[ret] = N % 10; 40 N = N / 10; 41 } 42 return ret; 43 } 44 45 void DP(ll len) 46 { 47 for(ll p = len; p > 0; p--) 48 { 49 for(ll d = 0; d <= 9; d++) 50 { 51 if(d == 7) continue; 52 for(ll i=0; i<7; i++) 53 { 54 for(ll j=0; j<7; j++) 55 { 56 ll ii,jj; 57 ii = (i+d)%7; 58 jj = (j*10+d)%7; 59 dp[p][1][ii][jj].sum += dp[p+1][1][i][j].sum*10
+ dp[p+1][1][i][j].num*d; 60 if(d < digits[p]) 61 dp[p][1][ii][jj].sum += dp[p+1][0][i][j].sum*10
+ dp[p+1][0][i][j].num*d; 62 dp[p][1][ii][jj].sum %= MOD; 63 64 dp[p][1][ii][jj].num += dp[p+1][1][i][j].num; 65 if(d < digits[p]) 66 dp[p][1][ii][jj].num += dp[p+1][0][i][j].num; 67 dp[p][1][ii][jj].num %= MOD; 68 69 dp[p][1][ii][jj].ssum += dp[p+1][1][i][j].ssum * 100LL
+ 20LL * d * dp[p+1][1][i][j].sum + d*d * dp[p+1][1][i][j].num; 70 if(d < digits[p]) 71 dp[p][1][ii][jj].ssum += dp[p+1][0][i][j].ssum * 100LL
+ 20LL * d * dp[p+1][0][i][j].sum + d*d * dp[p+1][0][i][j].num; 72 dp[p][1][ii][jj].ssum %= MOD; 73 } 74 } 75 } 76 ll d = digits[p]; 77 if(d == 7) continue; 78 for(ll i=0; i<7; i++) 79 { 80 for(ll j=0; j<7; j++)if(dp[p+1][0][i][j].num) 81 { 82 ll ii,jj; 83 ii = (i+d)%7; 84 jj = (j*10+d)%7; 85 dp[p][0][ii][jj].sum += dp[p+1][0][i][j].sum*10 + dp[p+1][0][i][j].num*d; 86 dp[p][0][ii][jj].sum %= MOD; 87 88 dp[p][0][ii][jj].num += dp[p+1][0][i][j].num; 89 dp[p][0][ii][jj].num %= MOD; 90 91 dp[p][0][ii][jj].ssum += dp[p+1][0][i][j].ssum * 100LL
+ 20LL * d * dp[p+1][0][i][j].sum + d*d * dp[p+1][0][i][j].num; 92 dp[p][0][ii][jj].ssum %= MOD; 93 } 94 } 95 } 96 } 97 98 ll calcu(ll N) 99 { 100 ll len = Len(N); 101 ini(len); 102 dp[len+1][0][0][0].num = 1; 103 DP(len); 104 ll ret = 0; 105 for(ll i=1; i<7; i++){ 106 for(ll j=1; j<7; j++){ 107 ret += dp[1][0][i][j].ssum; 108 ret += dp[1][1][i][j].ssum; 109 } 110 } 111 ret %= MOD; 112 return ret; 113 } 114 115 int main() 116 { 117 ll T; 118 cin >> T; 119 while(T--){ 120 ll A,B; 121 cin >> A >> B; 122 ll ans = 0; 123 ans = calcu(B) - calcu(A - 1); 124 ans = (ans + MOD) % MOD; 125 cout << ans << endl; 126 } 127 return 0; 128 }
posted on 2013-03-22 05:42 Lattexiaoyu 阅读(427) 评论(0) 编辑 收藏 举报