USACO 之 Section 2.2 (已解决)
Preface Numbering:
/*
发现规律,可生成出个、十、百、千的罗马数字。
然后,直接1~N枚举,统计字符出现次数。
*/
1 /* 2 ID: Jming 3 PROG: preface 4 LANG: C++ 5 */ 6 #include <iostream> 7 #include <fstream> 8 #include <sstream> 9 #include <cstdlib> 10 #include <cstdio> 11 #include <cstddef> 12 #include <iterator> 13 #include <algorithm> 14 #include <string> 15 #include <locale> 16 #include <cmath> 17 #include <vector> 18 #include <cstring> 19 #include <map> 20 #include <utility> 21 #include <queue> 22 #include <stack> 23 #include <set> 24 #include <functional> 25 using namespace std; 26 typedef pair<int, int> PII; 27 typedef long long int64; 28 const int INF = 0x3f3f3f3f; 29 const int modPrime = 3046721; 30 const double eps = 1e-9; 31 const int MaxN = (1<<8) + 10; 32 const int MaxM = 20; 33 34 const string sig = "IVXLCDM"; 35 vector<string> one; 36 vector<string> ten; 37 vector<string> hundred; 38 vector<string> thousand; 39 40 int N; 41 map<int, vector<string> > mapIS; 42 43 void ini(vector<string> &vecStr, string sign) 44 { 45 vecStr.push_back(""); 46 string str; 47 str = sign[0]; 48 for (int i = 0; i < 3; ++i) 49 { 50 vecStr.push_back(str); 51 str += sign[0]; 52 } 53 if (sign.size() == 1) 54 { 55 return; 56 } 57 str = sign[1]; 58 vecStr.push_back(sign[0] + str); 59 for (int i = 0; i < 4; ++i) 60 { 61 vecStr.push_back(str); 62 str += sign[0]; 63 } 64 str = sign[2]; 65 vecStr.push_back(sign[0] + str); 66 } 67 68 void Solve() 69 { 70 string str; 71 for (int i = 1; i <= N; ++i) 72 { 73 int num = i; 74 int cnt = 1; 75 while (num) 76 { 77 int digit = num % 10; 78 str = mapIS[cnt][digit] + str; 79 num /= 10; 80 ++cnt; 81 } 82 } 83 map<char, int> mapCI; 84 for (int i = 0; i < str.size(); ++i) 85 { 86 if (mapCI.find(str[i]) == mapCI.end()) 87 { 88 mapCI[str[i]] = 1; 89 } 90 else 91 { 92 ++mapCI[str[i]]; 93 } 94 } 95 for (int i = 0; i < 7; ++i) 96 { 97 if (mapCI.find(sig[i]) != mapCI.end()) 98 { 99 printf("%c %d\n", sig[i], mapCI[sig[i]]); 100 } 101 } 102 } 103 104 int main() 105 { 106 #ifdef HOME 107 freopen("in", "r", stdin); 108 //freopen("out", "w", stdout); 109 #endif 110 111 freopen("preface.in", "r", stdin); 112 freopen("preface.out", "w", stdout); 113 114 ini(one, "IVX"); 115 ini(ten, "XLC"); 116 ini(hundred, "CDM"); 117 ini(thousand, "M"); 118 119 mapIS[1] = one; 120 mapIS[2] = ten; 121 mapIS[3] = hundred; 122 mapIS[4] = thousand; 123 scanf("%d", &N); 124 Solve(); 125 126 127 #ifdef HOME 128 cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl; 129 #endif 130 return 0; 131 }
Subset Sums:
/*
01背包变形:
dp[i][j] := 前i个数,组成和恰为j的方式最大数目
dp[i][j] = dp[i-1][j] + dp[i-1][j-i] (j>=i)
空间优化
*/
1 /* 2 ID: Jming 3 PROG: subset 4 LANG: C++ 5 */ 6 #include <iostream> 7 #include <fstream> 8 #include <sstream> 9 #include <cstdlib> 10 #include <cstdio> 11 #include <cstddef> 12 #include <iterator> 13 #include <algorithm> 14 #include <string> 15 #include <locale> 16 #include <cmath> 17 #include <vector> 18 #include <cstring> 19 #include <map> 20 #include <utility> 21 #include <queue> 22 #include <stack> 23 #include <set> 24 #include <functional> 25 using namespace std; 26 typedef pair<int, int> PII; 27 typedef long long int64; 28 const int INF = 0x3f3f3f3f; 29 const int modPrime = 3046721; 30 const double eps = 1e-9; 31 const int MaxN = 40; 32 const int MaxM = 20; 33 34 int N; 35 int goal; 36 int ans = 0; 37 38 // 注意:需为long long类型 39 long long dp[(((1 + MaxN)*MaxN) >> 2) + 10]; 40 41 void Solve() 42 { 43 if ((((1 + N)*N) >> 1) % 2) 44 { 45 // 找不到 the sums of both subsets are identical 46 cout << 0 << endl; 47 return; 48 } 49 int goal = (((1 + N)*N) >> 2); 50 51 dp[0] = 1; 52 for (int i = 1; i <= N; ++i) 53 { 54 for (int j = goal; j >= i; --j) 55 { 56 dp[j] += dp[j - i]; 57 } 58 } 59 cout << (dp[goal] >> 1) << endl; 60 } 61 62 int main() 63 { 64 #ifdef HOME 65 freopen("in", "r", stdin); 66 //freopen("out", "w", stdout); 67 #endif 68 69 freopen("subset.in", "r", stdin); 70 freopen("subset.out", "w", stdout); 71 72 cin >> N; 73 Solve(); 74 75 #ifdef HOME 76 cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl; 77 #endif 78 return 0; 79 }
Runaround Numbers:
/*
仔细读题,利用hash思想,即可解决
*/
1 /* 2 ID: Jming 3 PROG: runround 4 LANG: C++ 5 */ 6 #include <iostream> 7 #include <fstream> 8 #include <sstream> 9 #include <cstdlib> 10 #include <cstdio> 11 #include <cstddef> 12 #include <iterator> 13 #include <algorithm> 14 #include <string> 15 #include <locale> 16 #include <cmath> 17 #include <vector> 18 #include <cstring> 19 #include <map> 20 #include <utility> 21 #include <queue> 22 #include <stack> 23 #include <set> 24 #include <functional> 25 using namespace std; 26 typedef pair<int, int> PII; 27 typedef long long int64; 28 const int INF = 0x3f3f3f3f; 29 const int modPrime = 3046721; 30 const double eps = 1e-9; 31 const int MaxN = 40; 32 const int MaxM = 20; 33 34 unsigned long N; 35 36 bool isLegal(unsigned long num) 37 { 38 char chStr[25]; 39 sprintf(chStr, "%d", num); 40 string str = chStr; 41 42 bool digit[10]; 43 fill(digit, digit + 10, false); 44 digit[0] = true; // none of which is zero 45 // unique digits 46 for (int i = 0; i < str.size(); ++i) 47 { 48 if (digit[str[i] - '0']) 49 { 50 return false; 51 } 52 digit[str[i] - '0'] = true; 53 } 54 55 bool isVisited[25]; 56 fill(isVisited, isVisited + 25, false); 57 int start = 0, Flag = 0; 58 // an interesting property 59 do 60 { 61 int pos = (start + (str[start] - '0')) % str.size(); 62 if ((pos == start) || isVisited[pos]) 63 { 64 return false; 65 } 66 isVisited[pos] = true; 67 start = pos; 68 } while (start != Flag); 69 for (int i = 0; i < str.size(); ++i) 70 { 71 if (!isVisited[i]) 72 { 73 return false; 74 } 75 } 76 return true; 77 } 78 79 void Solve() 80 { 81 unsigned long i = N + 1; 82 while (!isLegal(i)) 83 { 84 ++i; 85 } 86 cout << i << endl; 87 } 88 89 int main() 90 { 91 #ifdef HOME 92 freopen("in", "r", stdin); 93 //freopen("out", "w", stdout); 94 #endif 95 96 freopen("runround.in", "r", stdin); 97 freopen("runround.out", "w", stdout); 98 99 cin >> N; 100 Solve(); 101 102 #ifdef HOME 103 cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl; 104 #endif 105 return 0; 106 }
Party Lamps:
/*
首先N最大值100,C最大值为10000,有4个按钮。
第一思路,直接暴搜的话,(4^10000),必然超时。
所以,关键在于找出规律。。。
*************************************************************************************************
关键:两个规律
(1)只要考虑6个灯的状态就好了,编号大于6的灯x与编号为(x%6)的状态是一样的。(即每6个灯的状态是一个循环)
原因:
只考虑Button 1:每1个灯的状态是一个循环
只考虑Button 2:每2个灯的状态是一个循环
只考虑Button 3:每2个灯的状态是一个循环
只考虑Button 4:每3个灯的状态是一个循环
=> 取(1, 2, 2, 3)的最小公倍数,即:6
(2)首先我们知道一个button按两下,其实和没按这个button的效果是一样的。所以:
C=0:灯全亮(初始状态)
C=1:可能按了4个button中的任意1个
C=2:可能按了4个button中的任意2个 【或者】 相当于 C=0(存在有两下相互抵消)
C=3:可能按了4个button中的任意3个 【或者】 相当于 C=1(存在有两下相互抵消)
C=4:可能按了4个button中的任意4个 【或者】 相当于 C=2(存在有两下相互抵消)
可以类推至C>4的情况:
C=5:仅有4个开关,按了5下,必然至少有两下的作用相互抵消,所以:相当于 C=3
C=6:仅有4个开关,按了6下,必然至少有两下的作用相互抵消,所以:相当于 C=4
......
C=n:仅有4个开关,按了n下,必然至少有两下的作用相互抵消,所以:相当于 C=(n-2)
可递推知,对于C>4,分两种情况:
1) C>4且奇数,相当于 C=3
2) C>4且偶数,相当于 C=4
*************************************************************************************************
综合以上两个规律,只要求出C=0...4可能被按下的button即可(共2^4种按button的方式)。
*/
1 /* 2 ID: Jming 3 PROG: lamps 4 LANG: C++ 5 */ 6 #include <iostream> 7 #include <fstream> 8 #include <sstream> 9 #include <cstdlib> 10 #include <cstdio> 11 #include <cstddef> 12 #include <iterator> 13 #include <algorithm> 14 #include <string> 15 #include <locale> 16 #include <cmath> 17 #include <vector> 18 #include <cstring> 19 #include <map> 20 #include <utility> 21 #include <queue> 22 #include <stack> 23 #include <set> 24 #include <bitset> 25 #include <functional> 26 using namespace std; 27 typedef pair<int, int> PII; 28 typedef long long int64; 29 const int INF = 0x3f3f3f3f; 30 const int modPrime = 3046721; 31 const double eps = 1e-9; 32 const int MaxN = 40; 33 const int MaxM = 20; 34 35 int N; 36 int C; 37 vector<int> vecInt[5]; 38 vector<int> on; 39 vector<int> off; 40 set<string> setAns; 41 42 int button[4]; 43 44 void generateCombination(int pos, int cnt, int val, const int lim) 45 { 46 // 以val的第i位是否为1,记录在C=lim下,是否会按下按钮i 47 if (cnt == lim) 48 { 49 vecInt[lim].push_back(val); 50 return; 51 } 52 for (int i = pos; i < 4; ++i) 53 { 54 generateCombination(i + 1, cnt + 1, val|(1<<i), lim); 55 } 56 } 57 58 // 按下按钮 <=> 与button进行异或运算 59 void getButton() 60 { 61 // 1:When this button is pressed, all the lamps change their state. 62 fill(button, button + 4, 0); 63 button[0] = (1 << 6) - 1; 64 // 2:Changes the state of all the odd numbered lamps. 65 /*注:对应 二进制101010*/ 66 for (int i = 5; i >=0; i -= 2) 67 { 68 button[1] |= (1 << i); 69 } 70 // 3:Changes the state of all the even numbered lamps. 71 /*注:对应 二进制010101*/ 72 for (int i = 4; i >= 0; i -= 2) 73 { 74 button[2] |= (1 << i); 75 } 76 // 4: Changes the state of the lamps whose number is of the form 3xK+1 (with K>=0) 77 /*注:对应 二进制100100*/ 78 button[3] |= (1 << 2); 79 button[3] |= (1 << 5); 80 } 81 82 void ini() 83 { 84 getButton(); 85 86 // C=0...4时,可能被按下的button 87 vecInt[0].push_back(0); 88 for (int i = 1; i <= 4; ++i) 89 { 90 generateCombination(0, 0, 0, i); 91 } 92 vecInt[2].push_back(0); 93 for (int i = 0; i < vecInt[1].size(); ++i) 94 { 95 vecInt[3].push_back(vecInt[1][i]); 96 } 97 vecInt[4].push_back(0); 98 for (int i = 0; i < vecInt[2].size(); ++i) 99 { 100 vecInt[4].push_back(vecInt[2][i]); 101 } 102 } 103 104 // 十进制转换成二进制 eg:2D => 000010B 105 string tenTotwo(int num) 106 { 107 string str; 108 while (num) 109 { 110 if (num & 1) 111 { 112 str = static_cast<char>('0' + 1) + str; 113 } 114 else 115 { 116 str = '0' + str; 117 } 118 num >>= 1; 119 } 120 while (str.size() < 6) 121 { 122 str = '0' + str; 123 } 124 return str; 125 } 126 127 128 // 判断生成的结果是否合法 129 bool isLegal(string str) 130 { 131 for (int i = 0; i < on.size(); ++i) 132 { 133 if (str[(on[i] - 1)%6] != '1') 134 { 135 return false; 136 } 137 } 138 for (int i = 0; i < off.size(); ++i) 139 { 140 if (str[(off[i] - 1)%6] != '0') 141 { 142 return false; 143 } 144 } 145 return true; 146 } 147 148 void getAns(int c, int start) 149 { 150 for (int i = 0; i < vecInt[c].size(); ++i) 151 { 152 int val = vecInt[c][i]; 153 int startNum = start; 154 int cnt = 0; 155 while (val) 156 { 157 if (val & 1) 158 { 159 startNum ^= button[cnt]; 160 } 161 val >>= 1; 162 ++cnt; 163 } 164 string str = tenTotwo(startNum); 165 if (isLegal(str)) 166 { 167 setAns.insert(str); 168 } 169 } 170 } 171 172 void Solve() 173 { 174 ini(); 175 176 int start = (1 << 6) - 1; 177 if (C <= 4) 178 { 179 getAns(C, start); 180 } 181 else 182 { 183 if (C&1) 184 { 185 // C>4且奇数 186 getAns(3, start); 187 } 188 else 189 { 190 // C>4且偶数 191 getAns(4, start); 192 } 193 } 194 195 if (setAns.empty()) 196 { 197 printf("IMPOSSIBLE\n"); 198 } 199 else 200 { 201 for (set<string>::iterator it = setAns.begin(); it != setAns.end(); ++it) 202 { 203 string str = *it; 204 for (int i = 0; i < N; ++i) 205 { 206 printf("%c", str[i % 6]); 207 } 208 printf("\n"); 209 } 210 } 211 } 212 213 int main() 214 { 215 #ifdef HOME 216 freopen("in", "r", stdin); 217 //freopen("out", "w", stdout); 218 #endif 219 220 freopen("lamps.in", "r", stdin); 221 freopen("lamps.out", "w", stdout); 222 223 scanf("%d", &N); 224 scanf("%d", &C); 225 int num; 226 while ((scanf("%d", &num)) && (num != -1)) 227 { 228 on.push_back(num); 229 } 230 while ((scanf("%d", &num)) && (num != -1)) 231 { 232 off.push_back(num); 233 } 234 Solve(); 235 236 #ifdef HOME 237 cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl; 238 #endif 239 return 0; 240 }