SRM 403(1-250pt, 1-500pt)
DIV1 250pt
题意:称各个数位只含有4和7的数为lucky number,给定a,b,求[a, b]中的lucky number有多少个。a, b <= 10^9
解法:很明显的数位dp,写出来也就20行左右。本来以为最近刚好在做数位dp,可以很快出,结果我想着刚才做的那个数位dp,脑袋进水居然直接敲了段递归的代码还半天没调出来.......然后很快写了段非递归的代码过了.....160score...
后来看官方题解说,由于10^9内实际上只有1022个lucky number,所以可以求全部生成出来,看有哪些在[a, b]上。
tag:数位dp,think
1 // BEGIN CUT HERE 2 /* 3 * Author: plum rain 4 * score : 5 */ 6 /* 7 8 */ 9 // END CUT HERE 10 #line 11 "TheLuckyNumbers.cpp" 11 #include <sstream> 12 #include <stdexcept> 13 #include <functional> 14 #include <iomanip> 15 #include <numeric> 16 #include <fstream> 17 #include <cctype> 18 #include <iostream> 19 #include <cstdio> 20 #include <vector> 21 #include <cstring> 22 #include <cmath> 23 #include <algorithm> 24 #include <cstdlib> 25 #include <set> 26 #include <queue> 27 #include <bitset> 28 #include <list> 29 #include <string> 30 #include <utility> 31 #include <map> 32 #include <ctime> 33 #include <stack> 34 35 using namespace std; 36 37 #define CLR(x) memset(x, 0, sizeof(x)) 38 #define CLR1(x) memset(x, -1, sizeof(x)) 39 #define PB push_back 40 #define SZ(v) ((int)(v).size()) 41 #define ALL(t) t.begin(),t.end() 42 #define zero(x) (((x)>0?(x):-(x))<eps) 43 #define out(x) cout<<#x<<":"<<(x)<<endl 44 #define tst(a) cout<<#a<<endl 45 #define CINBEQUICKER std::ios::sync_with_stdio(false) 46 47 typedef vector<int> VI; 48 typedef vector<string> VS; 49 typedef vector<double> VD; 50 typedef pair<int, int> pii; 51 typedef long long int64; 52 53 const double eps = 1e-8; 54 const double PI = atan(1.0)*4; 55 const int maxint = 2139062143; 56 57 int dit[20], two[20]; 58 59 int gao(int x) 60 { 61 two[0] = 1; 62 for (int i = 1; i < 15; ++ i) 63 two[i] = two[i-1] * 2; 64 65 int len = 0; 66 while (x){ 67 dit[len++] = x % 10; 68 x /= 10; 69 } 70 71 int ret = 0; 72 for (int i = 1; i < len; ++ i) 73 ret += two[i]; 74 for (int i = len-1; i >= 0; -- i){ 75 if (4 < dit[i]) ret += two[i]; 76 if (7 < dit[i]) ret += two[i]; 77 if (dit[i] != 4 && dit[i] != 7) break; 78 } 79 return ret; 80 } 81 82 class TheLuckyNumbers 83 { 84 public: 85 int count(int a, int b){ 86 return gao(b+1) - gao(a); 87 } 88 89 // BEGIN CUT HERE 90 public: 91 void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); } 92 private: 93 template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); } 94 void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } } 95 void test_case_0() { int Arg0 = 1; int Arg1 = 1000000000; int Arg2 = 1022; verify_case(0, Arg2, count(Arg0, Arg1)); } 96 void test_case_1() { int Arg0 = 11; int Arg1 = 20; int Arg2 = 0; verify_case(1, Arg2, count(Arg0, Arg1)); } 97 void test_case_2() { int Arg0 = 74; int Arg1 = 77; int Arg2 = 2; verify_case(2, Arg2, count(Arg0, Arg1)); } 98 void test_case_3() { int Arg0 = 1000000; int Arg1 = 5000000; int Arg2 = 64; verify_case(3, Arg2, count(Arg0, Arg1)); } 99 100 // END CUT HERE 101 102 }; 103 104 // BEGIN CUT HERE 105 int main() 106 { 107 // freopen( "a.out" , "w" , stdout ); 108 TheLuckyNumbers ___test; 109 ___test.run_test(-1); 110 return 0; 111 } 112 // END CUT HERE
DIV1 500pt
题意:称各个数位只含有4和7的数为lucky number,称完全由来自vector<int> numbers(含有lucky number和也含有unlucky number)里面的lucky number组成,且每一个a[i]的末位数字和a[i+1]的首位数字均相同的序列为lucky sequence。给定vector<int> numbers和int n,求长度为n的lucky sequence有多少个。只要一个数不同,则lucky sequence视为不同。
解法:lucky number分为四种,分别为4开头4结尾的,4开头7结尾的,7开头4结尾的,7开头7结尾的。若a[i]属于第A类,且a[i+1]可以为B类,则从A向B连接一条有向边。这样,就相当于求长度为n的路径有多少条。
我最初的想法是二分,设f(x, s, e)表示求长度为x,从s类开始,从e类结束的路径有多少条,f(x, s, e)由 f(x/2, s, i) 和 f(x-x/2, i, e)求得。我以为这样二分以后时间复杂度降低了,实际上每次二分都有4个决策,时间复杂度反而提升了,于是我毫无悬念地TLE了。然后,我改了代码,把x / 2变成了x / 10000,即将x分为10001段来求,由于前面每一段长度均为x/10000,后面一段长度为x - x/10000,所以实际上只需要求20个东西,这样时间复杂度就降低到能接受的范围了。
虽然算是水过了这道题,还是蛮开心的.....
官方题解给出的方法是用矩阵快速幂优化。其实要构造这个并不难吧。。。当时想了一下用矩阵,怎么就没想出来呢。。。。
tag:矩阵乘法
1 // BEGIN CUT HERE 2 /* 3 * Author: plum rain 4 * score : 5 */ 6 /* 7 8 */ 9 // END CUT HERE 10 #line 11 "TheLuckySequence.cpp" 11 #include <sstream> 12 #include <stdexcept> 13 #include <functional> 14 #include <iomanip> 15 #include <numeric> 16 #include <fstream> 17 #include <cctype> 18 #include <iostream> 19 #include <cstdio> 20 #include <vector> 21 #include <cstring> 22 #include <cmath> 23 #include <algorithm> 24 #include <cstdlib> 25 #include <set> 26 #include <queue> 27 #include <bitset> 28 #include <list> 29 #include <string> 30 #include <utility> 31 #include <map> 32 #include <ctime> 33 #include <stack> 34 35 using namespace std; 36 37 #define CLR(x) memset(x, 0, sizeof(x)) 38 #define CLR1(x) memset(x, -1, sizeof(x)) 39 #define PB push_back 40 #define SZ(v) ((int)(v).size()) 41 #define ALL(t) t.begin(),t.end() 42 #define zero(x) (((x)>0?(x):-(x))<eps) 43 #define out(x) cout<<#x<<":"<<(x)<<endl 44 #define tst(a) cout<<#a<<endl 45 #define CINBEQUICKER std::ios::sync_with_stdio(false) 46 47 typedef vector<int> VI; 48 typedef vector<string> VS; 49 typedef vector<double> VD; 50 typedef pair<int, int> pii; 51 typedef long long int64; 52 53 const double eps = 1e-8; 54 const double PI = atan(1.0)*4; 55 const int maxint = 2139062143; 56 const int mod = 1234567891; 57 58 int64 cnt[4]; 59 pii temp[4]; 60 set<int> st; 61 int64 pat[4][4], d[40000][4][4]; 62 int64 an[40000][4]; 63 64 int gao(int x) 65 { 66 pii num; 67 num.second = x % 10; 68 while (x >= 10){ 69 int tmp = x % 10; 70 x /= 10; 71 if (tmp != 7 && tmp != 4) return -1; 72 } 73 num.first = x % 10; 74 for (int i = 0; i < 4; ++ i) 75 if (num == temp[i]) return i; 76 return -1; 77 } 78 79 int64 rec(int len, int s, int e) 80 { 81 if (!len) return s == e; 82 if (len == 1) return pat[s][e]; 83 84 if (len < 40000 && d[len][s][e] != -1) 85 return d[len][s][e]; 86 87 if (len < 40000){ 88 int haf = len / 2; 89 int64 &ret = d[len][s][e]; 90 ret = 0; 91 for (int i = 0; i < 4; ++ i) 92 ret = (ret + rec(haf, s, i) * rec(len-haf, i, e)) % mod; 93 return ret; 94 } 95 96 int haf = len / 40000; 97 CLR (an); 98 for (int i = 0; i < 4; ++ i) 99 an[0][i] = rec(haf, s, i); 100 for (int i = 1; i < 40000; ++ i) 101 for (int j = 0; j < 4; ++ j) 102 for (int k = 0; k < 4; ++ k) 103 an[i][j] = (an[i][j] + an[i-1][k] * rec(haf, k, j)) % mod; 104 int64 ret = 0; 105 for (int i = 0; i < 4; ++ i) 106 ret = (ret + an[39999][i] * rec(len-haf*40000, i, e)) % mod; 107 return ret; 108 } 109 110 class TheLuckySequence 111 { 112 public: 113 int count(vector <int> num, int len){ 114 temp[0] = make_pair(4,4); temp[1] = make_pair(4,7); 115 temp[2] = make_pair(7,4); temp[3] = make_pair(7,7); 116 117 CLR (cnt); st.clear(); 118 for (int i = 0; i < (int)num.size(); ++ i){ 119 int tmp = gao(num[i]); 120 if (tmp != -1 && !st.count(num[i])){ 121 ++ cnt[tmp]; 122 st.insert(num[i]); 123 } 124 } 125 CLR (pat); 126 for (int i = 0; i < 4; ++ i) 127 for (int j = 0; j < 4; ++ j) 128 if (temp[i].second == temp[j].first){ 129 pat[i][j] = cnt[i]; 130 } 131 132 CLR1 (d); 133 int64 ret = 0; 134 for (int i = 0; i < 4; ++ i) 135 for (int j = 0; j < 4; ++ j) 136 ret = (ret + rec(len-1, i, j) * cnt[j]) % mod; 137 return (int)ret; 138 } 139 140 // BEGIN CUT HERE 141 public: 142 void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); } 143 private: 144 template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); } 145 void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } } 146 void test_case_0() { int Arr0[] = {44, 47, 74, 77, 44, 47, 74, 77}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 1000000000; int Arg2 = 1133762585; verify_case(0, Arg2, count(Arg0, Arg1)); } 147 void test_case_1() { int Arr0[] = {47, 74, 47}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 3; int Arg2 = 2; verify_case(1, Arg2, count(Arg0, Arg1)); } 148 void test_case_2() { int Arr0[] = {100, 4774, 200, 747, 300}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 47; int Arg2 = 2; verify_case(2, Arg2, count(Arg0, Arg1)); } 149 void test_case_3() { int Arr0[] = {44, 47, 74, 77}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 2; int Arg2 = 8; verify_case(3, Arg2, count(Arg0, Arg1)); } 150 151 // END CUT HERE 152 153 }; 154 155 // BEGIN CUT HERE 156 int main() 157 { 158 // freopen( "a.out" , "w" , stdout ); 159 TheLuckySequence ___test; 160 ___test.run_test(-1); 161 return 0; 162 } 163 // END CUT HERE
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。