Codeforces Round #184 (Div.2)
这次真的很挫,写了三题竟然只过了一题,cf的数据强是一方面,再者也发现自己写代码时的一些细节部分没有注意,过来改了昨天两天代码都很快AC了。
这题只需要处理几种情况就可以了,100和0必须取,其他如果同时出现X0和X这样的数就取两个,否则XX、X、X0取中间任意一个。
代码如下:
#include <iostream> #include <cmath> #include <cstring> #include <cstdio> #include <string> #include <stdlib.h> #include <algorithm> using namespace std; typedef long long LL; const LL Mod= 1e9+7; int N, num[105]; int vis[105]; int a, b, c; int h, z; int first; // a 1 - 9 // b 10 - 90 // c 11 - 99 void output(int x) { if (first) { first = 0; printf("%d", x); } else { printf(" %d", x); } } void solve() { int cnt = 0; if (~h) ++cnt; if (~z) ++cnt; if (~a && ~b) { printf("%d\n", cnt+2); if (~h) output(h); if (~z) output(z); output(a), output(b); puts(""); return; } else { if (~a) { printf("%d\n", cnt+1); if (~h) output(h); if (~z) output(z); output(a); } else if (~b) { printf("%d\n", cnt+1); if (~h) output(h); if (~z) output(z); output(b); } else if (~c){ printf("%d\n", cnt+1); if (~h) output(h); if (~z) output(z); output(c); } else { printf("%d\n", cnt); if (~h) output(h); if (~z) output(z); } } puts(""); } int main() { int cnt; while (scanf("%d", &N) != EOF) { h = z = -1; a = b = c = -1; first = 1; int flag10 = 0, flag = 0; for (int i = 0; i < N; ++i) { scanf("%d", &num[i]); if (num[i] == 100) { h = 100; } else if (num[i] == 0){ z = 0; } else { if (num[i] < 10) a = num[i]; else if (num[i] % 10 == 0) b = num[i]; else c = num[i]; } } solve(); } return 0; }
每次把连分数的整数部分减掉,然后两边同时取倒数。我使用了long double来处理。
代码如下:
#include <iostream> #include <cmath> #include <cstring> #include <cstdio> #include <string> #include <stdlib.h> #include <algorithm> using namespace std; typedef long long LL; const LL Mod= 1e9+7; const long double eps = 1e-8; int sign(long double x) { return (x < -eps) ? -1 : (x > eps); } struct FENSHU { LL a, b; void swap() { LL t = a; a = b, b = t; } bool sub(LL x) { long double t = (long double)(1.0)*a/b; long double y = (long double)(1.0)*x; if (sign(t-y) >= 0) { a -= b*x; return true; } return false; } void show() { printf("%I64d/%I64d\n", a, b); } }NUM; LL seq[105]; int main() { LL n; while (scanf("%I64d %I64d", &NUM.a, &NUM.b) != EOF) { scanf("%I64d", &n); for (int i = 1; i <= n; ++i) { scanf("%I64d", &seq[i]); } int flag = true; for (int i = 1; i <= n; ++i) { if (!NUM.sub(seq[i])) { flag = false; } else { NUM.swap(); } } if (!flag || NUM.b) puts("NO"); else puts("YES"); } return 0; }
一个暴力的方法是高精度模拟2进制相加,最后查看最低位到最高位有多少个位置为0即可,但很可惜,这题的数据范围有点大。由于最多只有10^5个数,因此可以得知连续的这么多个数相加,不会超过20位的2进制位,因此我的想法是把这些数按照某个数指数小于等于它20以内进行分组,然后再一个一个组的求解。
代码入下:
#include <iostream> #include <cmath> #include <cstring> #include <cstdio> #include <string> #include <stdlib.h> #include <algorithm> using namespace std; typedef long long LL; const LL Mod= 1e9+7; int arr[100005]; int N; int path[100005]; int ret; int cal(int k) { int base = path[0]; int bit[50] = {0}; for (int i = 0; i < k; ++i) { path[i] -= base; bit[path[i]]++; } // for (int i = 0; i < 6; ++i) { // printf("bit[%d] = %d\n", i, bit[i]); // } for (int i = 0; i < 50; ++i) { int c = bit[i] / 2; bit[i+1] += c; bit[i] %= 2; } int p = 49; while (!bit[p]) --p; for (int i = 0; i < p; ++i) { if (!bit[i]) ++ret; } return p+base; } int main( ) { int x; while (scanf("%d", &N) != EOF) { memset(arr, 0, sizeof (arr)); ret = 0; for (int i = 0; i < N; ++i) { scanf("%d", &arr[i]); } if (N == 1) { printf("%d\n", arr[0]); } else { ret += arr[0]; path[0] = arr[0]; int k = 1, base = arr[0]; for (int i = 1; i < N; ++i) { if (arr[i]-base > 20) { int p = cal(k); ret += arr[i]-p-1; path[0] = arr[i]; base = arr[i]; k = 1; } else { path[k++] = arr[i]; } } cal(k); printf("%d\n", ret); } } return 0; }
未完...