按位dp:对于当前长度i是枚举该为的值(0~10),统计出区间内合法的数;
下面是基础入门的3题;
hdoj 2089 http://acm.hdu.edu.cn/showproblem.php?pid=2089 区间数内不包含4和62的数的个数
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 8 int num[10][10]; 9 10 // 预处理长度为i,取值为j时的合法元素个数; 11 void Pre(){ 12 memset(num, 0, sizeof num); 13 for ( int i=0; i<10; ++i ) 14 num[1][i] = 1; 15 num[1][4] = 0; 16 for ( int i=2; i<9; ++i ) 17 { 18 for ( int j=0; j<10; ++j ) if(j ^ 4) 19 for ( int k=0; k<10; ++k ) if(k ^ 4) 20 { 21 if(j==6 && k==2) continue; // 剔出非法的元素 22 num[i][j] += num[i-1][k]; 23 } 24 } 25 }; 26 27 int count( int n ) { 28 if(n <= 0) return 1; 29 int a[12] = {0}; 30 while(n ) { 31 a[++a[0] ] = n%10; n /= 10; 32 } 33 int ret = 0, last=-1; 34 while(a[0] > 0) { 35 int t = a[a[0] ]; 36 for ( int i=0; i<t; ++i ) { 37 if(i == 4) continue; 38 if(last==6 && i==2) continue; 39 ret += num[a[0] ][i]; 40 } 41 if(t^4 && a[0]==1 && !(last==6&&t==2)) ret += num[1][t]; 42 // 要考虑是否可以取最后一位 43 if(t == 4) break; // 后面的数据都是非法的 44 if(last==6 && t==2) break; // 后面的数都是非法的 45 last = t; 46 --a[0]; 47 } 48 //cout<<" " << ret << endl; 49 return ret; 50 } 51 52 int main(){ 53 Pre(); int L, R; 54 while( ~scanf("%d%d", &L, &R), L||R ) { 55 if(L > R) swap(L, R); 56 int l = count(L-1); 57 int r = count(R); 58 printf("%d\n", r-l); 59 } 60 };
hdoj http://acm.hdu.edu.cn/showproblem.php?pid=3555 统计区间出现字串49的个数
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 7 typedef __int64 ll; 8 9 ll dp[30][10][2]; 10 // dp[i][j][0] 表示长度为i取值为j的不合法的元素个数; 11 // dp[i][j][1] 表示长度为i取值为j的合法元素个数 12 13 void Pre(){ 14 memset(dp, 0, sizeof dp); 15 for ( int i=0; i<10; ++i ){ 16 dp[1][i][0] = 1; 17 } 18 for ( int i=2; i<30; ++i ) 19 { 20 for ( int j=0; j<10; ++j ) 21 for ( int k=0; k<10; ++k ){ 22 if(!(j==4 && k==9) ) 23 dp[i][j][0] += dp[i-1][k][0]; 24 dp[i][j][1] += dp[i-1][k][1]; 25 if(k == 9 && j == 4) 26 dp[i][j][1] += dp[i-1][k][0]; 27 } 28 } 29 //for ( int i=0; i<10; ++i ) 30 // cout << dp[4][i][1] <<" "; puts(""); 31 }; 32 33 // 这里也要注意数据类型 34 ll get(int *a, int l, int r){ 35 ll ret = 0; 36 for(int i=l; i>=r; --i) 37 ret = ret*10+a[i]; 38 return ret; 39 } 40 41 void count( ll n ){ 42 if(n < 49){ 43 puts("0"); return ; 44 } 45 int a[30]={0}; 46 while(n ) { 47 a[++a[0] ] = n%10; n /= 10; 48 } 49 ll ret = 0; 50 int last = -1; 51 while(a[0] > 1) { 52 int t = a[a[0] ]; 53 for ( int i=0; i<t; ++i ) 54 ret += dp[a[0] ][i][1]; 55 if(last==4 && t==9) { // 后面的数都是合法的,直接加上就可以了 56 ret += get(a, a[0]-1, 1)+1; 57 break; 58 } 59 if(a[0]==2 && a[a[0] ]==4 && a[a[0]-1 ]==9 ) ret++; 60 // 考虑最后一位是否可取 61 last = t; 62 --a[0]; 63 } 64 printf("%I64d\n", ret); 65 }; 66 67 int main(){ 68 Pre(); 69 int T; ll n; scanf("%d", &T); 70 while( T-- ) { 71 scanf("%I64d", &n); 72 count(n); 73 } 74 }
uestc http://acm.uestc.edu.cn/problem.php?pid=1307 统计区间内符合相邻数字差大于1的数;
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 typedef long long ll; 8 9 ll dp[15][12]; 10 bool ok(int x, int y){ 11 return abs(x-y)>1; 12 } 13 14 void Pre(){ 15 memset(dp, 0, sizeof dp); 16 for ( int i=0; i<10; ++i ) 17 dp[1][i] = 1; 18 for ( int i=2; i<12; ++i ){ 19 for ( int j=0; j<10; ++j ) 20 { 21 for ( int k=0; k<10; ++k )if(ok(j, k) ) { 22 dp[i][j] += dp[i-1][k]; 23 } 24 } 25 } 26 /* for(int j=1; j<=3; puts(""), ++j ) 27 for ( int i=0; i<10; ++i ) 28 cout << dp[j][i] << " ";*/ 29 } 30 31 ll count( ll x ) { 32 int a[14]={0}; 33 while( x ) { 34 a[++a[0] ] = x%10; x /= 10; 35 } 36 ll ret = 0; 37 for ( int i=1; i<a[0]; ++i ) 38 for ( int j=1; j<10; ++j ) 39 ret += dp[i][j]; 40 int last = 20; 41 while(a[0] > 0 ) { 42 int t = a[a[0] ]; 43 for ( int i=(last==20?1:0); i<t; ++i ) 44 if(ok(i, last) ) ret += dp[a[0] ][i]; 45 //if(a[0]==1 && ok(t, last) ) ret += dp[1][t]; 46 // 这个不要啊,前导0会枚举到这个情况,开始就因为这里得不到正确结果的 47 if(!ok(t, last) ) break; 48 last = t; 49 --a[0]; 50 } 51 // cout << " " << ret << endl; 52 return ret; 53 }; 54 55 int main(){ 56 Pre(); 57 ll L, R; 58 while( ~scanf("%lld%lld", &L, &R) ){ 59 ll l = count(L); 60 ll r = count(R+1); 61 printf("%lld\n", r-l); 62 } 63 };
以上都是些基础题,还有很多这样的题;
fzu 2070 http://acm.fzu.edu.cn/problem.php?pid=2070
zoj 2599 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2599
zoj 3162 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3162
zoj 3494 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3494
codeforces 55D http://www.codeforces.com/problemset/problem/55/D
codeforces 215E http://www.codeforces.com/problemset/problem/215/E
codeforces 258B http://www.codeforces.com/problemset/problem/258/B
。。。。。