Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 6509 | Accepted: 1773 |
Description
Input
Output
Sample Input
1 0 1 2 4 6 7
Sample Output
28
Source
题意:
0-9中不重复的几个数,若分成两堆分别组合成一个十进制数(首位不能是0),问两个数的差最小是多少?
思路:
假设总共有n个数,很显然一堆所使用的数字个数应该为n/2,另一堆用剩下的。先选择n/2个数,利用全排列性质遍历所有排列顺序,也就遍历了第一个数,对第二个数也类似遍历,求其差的最小值即可。
C++中提供的
next_permutation
函数在帮助遍历全排列时可提供很大帮助。
代码:
Source Code Problem: 2718 User: liangrx06 Memory: 204K Time: 469MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int INF = 1000000; int a[10]; int n; void input() { n = 0; char ch; while ( (ch = getchar()) != '\n' ) { if (ch == ' ') continue; a[n++] = ch - '0'; } } void solve() { int res = INF; int half = n/2; int i, x, y; do { if (half >= 2 && a[0] == 0) continue; if (n - half >= 2 && a[half] == 0) continue; x = 0; for (i = 0; i < half; i ++) x = x * 10 + a[i]; y = 0; for (i = half; i < n; i ++) y = y * 10 + a[i]; int tmp = (x > y) ? (x - y) : (y - x); if (tmp < res) res = tmp; } while (next_permutation(a, a + n)); printf("%d\n", res); } int main(void) { int t; cin >> t; getchar(); while (t--) { input(); solve(); } return 0; }
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 5409 | Accepted: 3121 |
Description
3 1 2 4 4 3 6 7 9 16Behind FJ's back, the cows have started playing a more difficult game, in which they try to determine the starting sequence from only the final total and the number N. Unfortunately, the game is a bit above FJ's mental arithmetic capabilities.
Input
Output
Sample Input
4 16
Sample Output
3 1 2 4
Hint
Source
题意:
给定1-n的某个排列,对其相邻的两个数相加得到n-1个数的数列,重复相加过程最终将得到一个数。
现在已知n以及操作后最终的结果sum,求原始排列(输出字典序最小的那个)。
思路:
简单分析后可以知道,原始排列中每个数的累加次数对应于n的二项式分解系数C(n,i)。对1-n的排列进行字典序遍历,第一个符合结果的排列就是答案。
代码:
Source Code Problem: 3187 User: liangrx06 Memory: 204K Time: 16MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int INF = 1000000; int a[10]; int n; int c[10]; int fact(int x) { int res = 1; while (x) res *= x--; return res; } void init() { int i; for (i = 0; i < 10; i ++) { a[i] = i+1; if (i < n) c[i] = fact(n-1)/fact(i)/fact(n-1-i); } } void solve(int sum) { int i; do { int tmp = 0; for (i = 0; i < n; i ++) tmp += a[i] * c[i]; if (tmp == sum) break; } while (next_permutation(a, a + n)); for (i = 0; i < n-1; i ++) printf("%d ", a[i]); printf("%d\n", a[i]); } int main(void) { int sum; while (cin >> n >> sum) { init(); solve(sum); } return 0; }
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2775 | Accepted: 1941 |
Description
Input
Output
Sample Input
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1
Sample Output
15
Hint
Source
题意:
给定一片5*5的土地,一只牛在上面初始任意位置,它每次可以上下左右直线跳到任意位置。求牛跳5次所形成的的路径(比如111121)的个数。
思路:
递归穷竭搜索。
我的程序中考虑了路径重复问题,因此存储路径使用了set(其中无重复元素)。但特殊数据结构的维护似乎抵消了存储复杂度降低所带来的好处,因而时间复杂度仍不算低。
代码:
Source Code Problem: 3050 User: liangrx06 Memory: 1064K Time: 219MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <set> using namespace std; int a[5][5]; set<int> s[2][5][5]; void input() { int i, j; for (i = 0; i < 5; i ++) { for (j = 0; j < 5; j ++) { cin >> a[i][j]; } } } void solve() { int i, j, k, x, y; set<int>::iterator it; int pos[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; for (k = 0; k < 6; k ++) { for (i = 0; i < 5; i ++) { for (j = 0; j < 5; j ++) { if (k == 0) { s[k&1][i][j].insert(a[i][j]); continue; } s[k&1][i][j].clear(); for (int m = 0; m < 4; m ++) { x = i + pos[m][0]; y = j + pos[m][1]; if (x >= 0 && x < 5 && y >= 0 && y < 5) { for (it = s[(k-1)&1][x][y].begin(); it != s[(k-1)&1][x][y].end( ); it ++) s[k&1][i][j].insert((*it)*10 + a[i][j]); } } } } } set<int> sall; for (i = 0; i < 5; i ++) { for (j = 0; j < 5; j ++) { for (it = s[1][i][j].begin(); it != s[1][i][j].end(); it ++) sall.insert((*it)); } } printf("%d\n", sall.size()); } int main(void) { input(); solve(); return 0; }
原题链接:
AOJ0525
题意:
题目大意是说,有一个煎饼器,可以烤R行C列的煎饼,煎饼可以正面朝上(用1表示),也可以背面朝上(用0表示),一次可以翻转一整行或一整列的煎饼。现在需要把尽量多的煎饼翻成正面朝上,给定煎饼的当前状态,问经过翻转后,最多能使多少煎饼正面朝上。
思路:
因为列数很大,行数只有10,所以枚举出10行所有的情况只有 210=1024 种可能性。行翻转完毕后,统计每一行朝上的和朝下的个数,取最大值即可。
枚举的话,先从行开始,一共有 2R 种翻转可能,行翻转完毕再翻转列。列的翻转不必真的flip,只需要统计一下朝上的煎饼果子和朝下的煎饼果子,两者比较取其最大值即可。另外需要注意循环内外层不能弄反,我就是因为弄反了一直出错。
我看其他很多人用了bitset,关注了一下运行时间发现并无优势,自己用位操作照样实现的很好。
代码:
#include <iostream> #include <cstdio> using namespace std; const int C = 10000; int r, c; int a[C]; void input() { cin >> r >> c; fill(a, a+c, 0); int x, n = 1; for (int i = 0; i < r; i ++) { for (int j = 0; j < c; j ++) { scanf("%d", &x); a[j] |= (x ? n : 0); } n <<= 1; } } void solve() { int res = 0; for (int k = 0; k < (1<<r); k ++) { int count = 0; for (int j = 0; j < c; j ++) { int count0 = 0, n = 1; for (int i = 0; i < r; i ++) { if ((a[j]^k)&n) count0 ++; n <<= 1; } count += ( (count0 > r/2) ? count0 : (r-count0) ); } res = (res > count) ? res : count; } printf("%d\n", res); } int main(void) { while (cin >> r >> c) { if (!r && !c) break; fill(a, a+c, 0); int x, n = 1; for (int i = 0; i < r; i ++) { for (int j = 0; j < c; j ++) { scanf("%d", &x); a[j] |= (x ? n : 0); } n <<= 1; } solve(); } return 0; }