SRM 510 2 250TheAlmostLuckyNumbersDivTwo
Problem Statement
John and Brus believe that the digits 4 and 7 are lucky and all others are not. According to them, an almost lucky number is a number that contains at most one non-lucky digit in its decimal representation. Return the total number of almost lucky numbers between a and b, inclusive.
Definition
- ClassTheAlmostLuckyNumbersDivTwo
- Methodfind
- Parametersint , int
- Returnsint
- Method signatureint find(int a, int b)
Limits
- Time limit (s)2.000
- Memory limit (MB)64
Constraints
- a will be between 1 and 1,000,000, inclusive.
- b will be between a and 1,000,000, inclusive.
Test cases
- a4
- b7
Returns4
All numbers between 4 and 7 are almost lucky.- a8
- b19
Returns4
Numbers 8, 9, 14 and 17 are almost lucky.- a28
- b33
Returns0
No almost lucky numbers here.- a1234
- b4321
Returns36
This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.
#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <typeinfo>
#include <fstream> using namespace std;
int dp[][] , dp2[][];
int dig[] ;
int vis[] ; void init ()
{
memset (dp , , sizeof(dp)) ;
memset (dp2 , , sizeof(dp2) ) ;
for (int i = ; i < ; i ++) dp[][i] = ;
for (int i = ; i <= ; i ++ ) {
for (int j = ; j < ; j ++) {
dp[i][j] += dp[i-][] + dp[i-][] ;
}
}
int a , b , c = , d = ;
for (int i = ; i <= ; i ++) for (int j = ; j < ; j ++) dp2[i][j] = dp[i][j] ;
for (int i = ; i <= ; i ++) {
a = dp[i][] , b = dp[i][] ;
for (int j = ; j < ; j ++) {
if (!(j == || j == )) {
dp2[i][] += dp[i-][j] ;
dp2[i][] += dp[i-][j] ;
}
else if (j == ) {
dp2[i][] += c ;
dp2[i][] += c ;
}
else if (j == ) {
dp2[i][] += d ;
dp2[i][] += d ;
}
}
// printf ("dp[%d][4]=%d , dp[%d][7]=%d\n" , i , dp[i][4] , i , dp[i][7]) ;
c = dp2[i][] - a , d = dp2[i][] - b ;
}
} int cal (int x)
{
memset (dig , , sizeof(dig)) ;
memset (vis , , sizeof(vis)) ;
int ans = ;
int len = ;
int tmp = x ;
int cnt = ;
while (x) {
dig[len ++] = x % ;
x /= ;
}
for (int i = len - ; i >= ; i --) {
vis[i] = cnt ;
if (dig[i] != && dig[i] != ) cnt ++ ;
}
//for (int i = 0 ; i < dig[1] ; i ++) ans += dp[1][i] ;
// ans += 10 ;
// printf ("hahaha") ;
// printf ("%d " , vis[0]) ;
// for (int i = 1 ; i < len ; i ++) printf ("%d " , vis[i]) ; puts ("") ;
for (int i = ; i < len ; i ++) {
printf ("vis[%d]=%d:\n\n" , i , vis[i] ) ;
if (vis[i] == ) {
for (int j = ; j < dig[i] ; j ++) ans += dp2[i][j] ;
}
else if (vis[i] == ) {
for (int j = ; j < dig[i] ; j ++) if (j == || j == ) ans += dp[i][j] , printf ("dp[%d][%d]=%d\n" , i , j , dp[i][j]) ;
}
if (i == len - ) ans -= dp[i][] ;
}
printf ("ans = %d\n" , ans ) ;
if (len == ) {
ans += dp[][] ;
}
else {
ans += dp[][] ;
for (int i = ; i < len - ; i ++) {
for (int j = ; j < ; j ++) ans += dp2[i][j] ;
}
}
printf ("%d:ans = %d\n" , tmp , ans) ;
printf ("-----------------------------------\n") ;
return ans ;
} class TheAlmostLuckyNumbersDivTwo {
public:
int find(int a, int b) {
puts ("") ;
if (a > b) swap(a,b) ;
init () ;
printf ("%d ~ %d\n" , a , b) ;
// printf ("%d - %d\n" , cal(b) , cal(a-1)) ;
return cal(b+) - cal(a) ;
//return 0 ;
}
}; // CUT begin
ifstream data("TheAlmostLuckyNumbersDivTwo.sample"); string next_line() {
string s;
getline(data, s);
return s;
} template <typename T> void from_stream(T &t) {
stringstream ss(next_line());
ss >> t;
} void from_stream(string &s) {
s = next_line();
} template <typename T>
string to_string(T t) {
stringstream s;
s << t;
return s.str();
} string to_string(string t) {
return "\"" + t + "\"";
} bool do_test(int a, int b, int __expected) {
time_t startClock = clock();
TheAlmostLuckyNumbersDivTwo *instance = new TheAlmostLuckyNumbersDivTwo();
int __result = instance->find(a, b);
double elapsed = (double)(clock() - startClock) / CLOCKS_PER_SEC;
delete instance; if (__result == __expected) {
cout << "PASSED!" << " (" << elapsed << " seconds)" << endl;
return true;
}
else {
cout << "FAILED!" << " (" << elapsed << " seconds)" << endl;
cout << " Expected: " << to_string(__expected) << endl;
cout << " Received: " << to_string(__result) << endl;
return false;
}
} int run_test(bool mainProcess, const set<int> &case_set, const string command) {
int cases = , passed = ;
while (true) {
if (next_line().find("--") != )
break;
int a;
from_stream(a);
int b;
from_stream(b);
next_line();
int __answer;
from_stream(__answer); cases++;
if (case_set.size() > && case_set.find(cases - ) == case_set.end())
continue; cout << " Testcase #" << cases - << " ... ";
if ( do_test(a, b, __answer)) {
passed++;
}
}
if (mainProcess) {
cout << endl << "Passed : " << passed << "/" << cases << " cases" << endl;
int T = time(NULL) - ;
double PT = T / 60.0, TT = 75.0;
cout << "Time : " << T / << " minutes " << T % << " secs" << endl;
cout << "Score : " << * (0.3 + (0.7 * TT * TT) / (10.0 * PT * PT + TT * TT)) << " points" << endl;
}
return ;
} int main(int argc, char *argv[]) {
cout.setf(ios::fixed, ios::floatfield);
cout.precision();
set<int> cases;
bool mainProcess = true;
for (int i = ; i < argc; ++i) {
if ( string(argv[i]) == "-") {
mainProcess = false;
} else {
cases.insert(atoi(argv[i]));
}
}
if (mainProcess) {
cout << "TheAlmostLuckyNumbersDivTwo (250 Points)" << endl << endl;
}
return run_test(mainProcess, cases, argv[]);
}
// CUT end
数位dp,,,,蛮有趣的,写了我三天,还好现在是考试季。数位dp能大大减少复杂度,拿这道题来说。如果用暴力来做要O(1e6),但用数位dp来的话,只需O(70)!!!!!
但同时换来的是复杂的构造。
推荐:http://www.cnblogs.com/archimedes/p/numerical-digit-dp.html