NOIP2012提高组解题报告

Day1T1

太长了不复制了, 看这里http://wikioi.com/problem/1197/

简单的字符串替换问题.

 1 #include <stdio.h>
 2 #include <string.h>
 3 char k[102], str[1002];
 4 int main()
 5 {
 6     scanf("%s%s", k, str);
 7     for (int i = 0, len = strlen(k); i < len; ++i)
 8         if (k[i] >= 'A' && k[i] <= 'Z')
 9             k[i] = 'a' + (k[i] - 'A');
10     for (int i = 0, p = 0, len = strlen(str), lenk = strlen(k); i < len; ++i, ++p, p = (p == lenk ? 0 : p))
11         if (str[i] >= 'A' && str[i] <= 'Z')
12         {
13             str[i] = str[i] - (k[p] - 'a');
14             if (str[i] - 'A' < 0)
15                 str[i] += 26;
16         }
17         else
18         {
19             str[i] = str[i] - (k[p] - 'a');
20             if (str[i] - 'a' < 0)
21                 str[i] += 26;
22         }
23     printf("%s\n", str);
24     return 0;
25 }

Day1T2

题目:http://wikioi.com/problem/1198/

给出一些二元组(Ai, Bi), 将他们按某种顺序排列. 对于每个二元组, 有一个值Fi, 计算方式是他之前所有二元组的Ai乘起来, 除以该二元组的Bi. 使得Max{F1, F2, F3 ... Fn}最小.

考虑交换相邻两个二元组的影响, 交换二元组i和二元组i+1,实际上只影响到Fi和Fi+1。

设T = A1 * A2 * ... * Ai-2 * Ai-1

方案A: Fi = T / Bi, Fi+1 =T * Ai / Bi+1

方案B: Fi = T / Bi+1, Fi+1 =T * Ai+1 / Bi

假设1 / Bi < Ai / Bi+1, 1 / Bi+1 < Ai+1 / Bi

那么方案A优于方案B(Ai / Bi+1 < Ai+1 / Bi, Ai * Bi < Ai+1 * B i+1)

假设1 / Bi ≥ Ai / Bi+1(Ai * Bi ≤ Bi+1)

那么1 / Bi ≤ Ai+1 / Bi, 方案A更优

假设1 / Bi+1 ≥ Ai+1 / Bi(Ai+1 * Bi+1 ≤ Bi)

那么1 / Bi+1 ≤ Ai / Bi+1, 方案B更优

也就是说, 对于相邻两个二元组, 将A * B的较小的放在前面总能使答案更优.

实现要使用高精度, 结束.

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #define MAXN 1001
  5 struct Person
  6 {
  7     int a, b;
  8 } p[MAXN];
  9 struct High
 10 {
 11     int len;
 12     int num[4001];
 13 };
 14 int n;
 15 bool operator < (Person n1, Person n2)
 16 {
 17     return n1.a * n1.b < n2.a * n2.b;
 18 }
 19 bool operator > (High n1, High n2)
 20 {
 21     if (n1.len > n2.len)
 22         return true;
 23     if (n1.len < n2.len)
 24         return false;
 25     for (int i = n1.len - 1; i > -1; --i)
 26     {
 27         if (n1.num[i] > n2.num[i])
 28             return true;
 29         if (n1.num[i] < n2.num[i])
 30             return false;
 31     }
 32     return true;
 33 }
 34 High operator * (High n1, int number)
 35 {
 36     int k = 0;
 37     n1.len += 5;
 38     for (int i = 0; i < n1.len; ++i)
 39         n1.num[i] *= number;
 40     for (int i = 0; i < n1.len; ++i)
 41     {
 42         n1.num[i] += k;
 43         k = n1.num[i]/10;
 44         n1.num[i] %= 10;
 45     }
 46     while (n1.num[n1.len - 1] == 0)
 47         --n1.len;
 48     return n1;
 49 }
 50 High operator / (High n1, int number)
 51 {
 52     High ans;
 53     memset(ans.num, 0, sizeof ans.num);
 54     ans.len = 0;
 55     int now = 0;
 56     for (int i = n1.len - 1; i > -1; --i)
 57     {
 58         now = now * 10 + n1.num[i];
 59         if (now < number && ans.len == 0)
 60             continue;
 61         ans.num[ans.len++] = now / number;
 62         now %= number;
 63     }
 64     for (int i = 0; i < ans.len / 2; ++i)
 65         std::swap (ans.num[i], ans.num[ans.len - i - 1]);
 66     return ans;
 67 }
 68 void Give(High *n1, int number)
 69 {
 70     memset (n1 -> num, 0, sizeof n1->num);
 71     n1 -> len = 0;
 72     do
 73     {
 74         n1 -> num[(n1 -> len)++] = number % 10;
 75         number /= 10;
 76     }
 77     while (number != 0);
 78 }
 79 void Print(High n1)
 80 {
 81     for (int i = n1.len - 1; i > -1; --i)
 82         printf("%d", n1.num[i]);
 83     printf("\n");
 84 }
 85 void Init()
 86 {
 87     scanf("%d", &n);
 88     for (int i = 0; i <= n; ++i)
 89         scanf("%d %d", &p[i].a, &p[i].b);
 90     for (int i = 1, j; i < n; ++i)
 91         for (j = i + 1; j <= n; ++j)
 92             if (!(p[i] < p[j]))
 93                 std::swap (p[i], p[j]);
 94 }
 95 int main()
 96 {
 97     Init();
 98     High s, maxx;
 99     Give(&s,p[0].a);
100     Give(&maxx,0);
101     for (int i = 1; i <= n; ++i)
102     {
103         if (s / p[i].b > maxx)
104             maxx = s / p[i].b;
105         s = s * p[i].a;
106     }
107     Print(maxx);
108     return 0;
109 }

Day1T3开车旅行

题目:http://wikioi.com/problem/1199/

对每个i点维护nextA[i], nextB[i]表示i往后A的话去哪里, B的话去哪里. 这个可以用链表来计算, 我们把所有数从小到大排序, 然后串成一个链表. 从1到n每次找Hi在链表里的前后4个判断一下, 然后把Hi从链表里删掉. 然后这样我们再用nextAB[i]表示i往后A走一次B走一次到哪里. 那么可以发现i->nextAB[i]形成了一颗树. 之后可以用树的算法做. 不过最简单的还是预处理next[i][j]表示i往后A和B都走了2^j次到哪里. 然后从大到小判2的每个次幂.

写的我太难受了, 连平时喜欢纠结的格式都没纠结成.

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cstring>
  7 #include <set>
  8 using namespace std;
  9 #define N 101000
 10 #define L 14
 11 #define INF 0x3f3f3f3f
 12 const double EPS = 1e-8;
 13 struct City
 14 {
 15  int h, id;
 16  inline City(): h(0), id(0) {
 17  }
 18  inline City(int h, int id): h(h), id(id) {
 19  }
 20  inline bool operator ==(const City &p) const {
 21   return (p.id == id);
 22  }
 23 }nexB[N], nexA[N];
 24 struct Dist
 25 {
 26  int a, b, dis, id;
 27  inline Dist(): a(0), b(0), dis(INF), id(0) {
 28  }
 29  inline Dist(int a, int b, int dis, int id): a(a), b(b), dis(dis), id(id) {
 30  }
 31  inline Dist operator +(const Dist &p) const {
 32   return Dist(a + p.a, b + p.b, dis + p.dis, p.id);
 33  }
 34 }f[N][L], c;
 35 inline bool cmp1(const City &a, const City &b) {return a.h < b.h;}
 36 inline bool cmp2(const City &a, const City &b) {return a.h > b.h;}
 37 bool (*cp1)(const City &, const City &) = cmp1, (*cp2)(const City &, const City &) = cmp2;
 38 set <City, bool(*)(const City &, const City &)> lr(cp1), hr(cp2);
 39 int n, m, h[N];
 40 inline void Update(int &dis, int dis1, City &CC, set <City>::iterator iter)
 41 {
 42  if ((dis > dis1) || (dis == dis1 && CC.h > (iter -> h))) dis = dis1, CC = *(iter);
 43 }
 44 inline City nex_B(const City &now, set<City>::iterator liter, set<City>::iterator hiter)
 45 {
 46  City CC; int dis = INF;
 47  int co = 1;
 48  for (set<City>::iterator iter = liter; co <= 1 && iter != lr.end(); iter ++, co ++) Update(dis, abs(now.h - (iter -> h)), CC, iter);
 49  co = 1;
 50  for (set<City>::iterator iter = hiter; co <= 1 && iter != hr.end(); iter ++, co ++) Update(dis, abs(now.h - (iter -> h)), CC, iter);
 51  if (dis == INF) return City();
 52  return CC;
 53 }
 54 inline City nex_A(const City &now, set<City>::iterator liter, set<City>::iterator hiter)
 55 {
 56  City fir = nex_B(now, liter, hiter);
 57  City CC; int dis = INF;
 58  int co = 1;
 59  for (set<City>::iterator iter = liter; co <= 2 && iter != lr.end(); iter ++, co ++) if (!((*iter) == fir)) Update(dis, abs(now.h - (iter -> h)), CC, iter);
 60  co = 1;
 61  for (set<City>::iterator iter = hiter; co <= 2 && iter != hr.end(); iter ++, co ++) if (!((*iter) == fir)) Update(dis, abs(now.h - (iter -> h)), CC, iter);
 62  if (dis == INF) return City();
 63  return CC;
 64 }
 65 void init()
 66 {
 67  scanf("%d", &n);
 68  for (int i = 1; i <= n; i ++) scanf("%d", &h[i]);
 69  for (int i = n; i >= 1; i --) {
 70   lr.insert(City(h[i], i)), hr.insert(City(h[i], i));
 71   set<City>::iterator liter = ++ lr.lower_bound(City(h[i], i)), hiter = ++ hr.lower_bound(City(h[i], i));
 72   City j = nex_A(City(h[i], i), liter, hiter); nexA[i] = j; nexB[i] = nex_B(City(h[i], i), liter, hiter);
 73   if (j == City()) continue ;
 74   int a = abs(h[i] - j.h), hj = j.h, b; j = nexB[j.id];
 75   if (j == City()) continue ; b = abs(hj - j.h);
 76   f[i][0] = Dist(a, b, a + b, j.id);
 77   for (int j = 1; j < L; j ++)
 78    if (f[f[i][j - 1].id][j - 1].dis != INF) f[i][j] = f[i][j - 1] + f[f[i][j - 1].id][j - 1];
 79  }
 80 }
 81 inline Dist go(int s, int x)
 82 {
 83  Dist CC = Dist(0, 0, 0, s);
 84  for (int i = L - 1; i >= 0; i --)
 85   if ((CC + f[CC.id][i]).dis <= x) CC = CC + f[CC.id][i];
 86  City nex = nexA[CC.id];
 87  if ((!(nex == City())) && (CC.dis + abs(h[CC.id] - nex.h) <= x)) CC = CC + Dist(abs(h[CC.id] - nex.h), 0, abs(h[CC.id] - nex.h), nex.id);
 88  return CC;
 89 }
 90 void solve()
 91 {
 92  double CC = (double) INF;
 93  int id = 0, x0, s, x;
 94  bool flag = false;
 95  scanf("%d", &x0);
 96  for (int i = 1; i <= n; i ++) {
 97   c = go(i, x0);
 98   if (c.b != 0 && ((double) c.a / (double)c.b < CC || (fabs((double) c.a / (double) c.b == CC)) && h[i] > h[id])) CC = (double) c.a / (double) c.b, id = i, flag = true;
 99  }
100  if (!flag) cout << hr.begin() -> id << endl; else cout << id << endl;
101  scanf("%d", &m);
102  for (int i = 1; i <= m; i ++)
103   scanf("%d%d", &s, &x), c = go(s, x), printf("%d %d\n", c.a, c.b);
104 }
105 int main()
106 {
107  init();
108  solve();
109  return 0;
110 }

Day2T1同余方程

求关于 x 同余方程 ax ≡ 1 (mod b)的最小正整数解.

一句话: 用exgcd或则利用结论a^(phi(b)-1)%b.

 1 #include <stdio.h>
 2 typedef long long int64;
 3 int64 stack_k[8193];
 4 int top = -1;
 5 int64 extended_euclidian_algo(int64 x, int64 y)
 6 {
 7     int64 a = x, b = y, p, q;
 8     while (b != 0ll)
 9     {
10         stack_k[++top] = (a / b) % y;
11         int64 t = a % b;
12         a = b;
13         b = t;
14     }
15     p = 1ll;
16     q = 0ll;
17     while (top != -1)
18     {
19         int64 t = (p - q * stack_k[top--] % y) % y;
20         if (t < 0)
21             t += y;
22         p = q;
23         q = t;
24     }
25     return p;
26 }
27 int main()
28 {
29     int64 a, b;
30     scanf("%I64d %I64d", &a, &b);
31     scanf("%I64d\n", extended_euclidian_algo(a, b));
32     return 0;
33 }

Day2T2借教室

题目:http://wikioi.com/problem/1217/

标准解法是:让我们考虑现在有m个操作,我们先把这些操作的端点离散化一下,之后可以注意到,相邻的两个关键点之间,只有最少的哪天是有用的,那么我们可以把天数压到2m级别。然后有m个操作,我们先加入前m/2个,然后用部分和判断一下前m/2个会不会跪,会的话就在前m/2个中递归,不然就在后m/2个中递归。由于我们每次可以压天数。复杂度函数就是F(n)=n+F(n/2)=O(n).

然后我很纠结的写了个二分...

 1 #include <math.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 #define N 1004000
 6 int a[N], sum[N], n, m, d[N];
 7 struct query
 8 {
 9  int x, y, d;
10 }q[N];
11 inline int Read()
12 {
13  char ch = getchar();
14  while (!(ch >= '0' && ch <= '9')) ch = getchar();
15  int x = 0;
16  while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
17  return x;
18 }
19 void init()
20 {
21  scanf("%d%d", &n, &m);
22  for (int i = 1; i <= n; i ++) a[i] = Read();
23  for (int i = 1; i <= m; i ++) q[i].d = Read(), q[i].x = Read(), q[i].y = Read();//scanf("%d%d%d", &q[i].d, &q[i].x, &q[i].y);
24 }
25 bool check(int m)
26 {
27  memset(d, 0, sizeof(d));
28  for (int i = 1; i <= m; i ++) d[q[i].x] += q[i].d, d[q[i].y + 1] -= q[i].d;
29  for (int i = 1; i <= n; i ++) {
30   sum[i] = sum[i - 1] + d[i];
31   if (sum[i] > a[i]) return false;
32  }
33  return true;
34 }
35 int find(int l, int r)
36 {
37  int mid = (l + r) >> 1;
38  while (l <= r) {
39   if (check(mid)) l = mid + 1;
40   else r = mid - 1;
41   mid = (l + r) >> 1;
42  }
43  return r;
44 }
45 int main()
46 {
47  init();
48  int CC = find(0, m);
49  if (CC == m) {puts("0\n");return 0;}
50  printf("%d\n%d\n", -1, CC + 1);
51  return 0;
52 }

Day2T3没时间写, 改天写.

原文地址:https://www.cnblogs.com/hatsuakiratenan/p/3132472.html