zoukankan      html  css  js  c++  java
  • NOIP模拟测试12

    I boom boom boom

    Problem A:斐波那契(fibonacci)

    题目名字就叫fibonacci,肯定要往这个方向想。

    手玩那棵树,可以发现儿子与父亲的差是小于儿子的最大的fib数列的项。

    开个set,一边用x减它能减的最大的fib的项来找爸爸一边往set里塞,然后一边减y一边在set里查,查见了输出就完事了。

    不必担心时间复杂度问题,fib增长飞快,fib[60]就已经超过1e13了。

    gmk手写hashtable太勇了(

     1 #include <bits/stdc++.h>
     2 
     3 long long fib[65], x, y;
     4 int m;
     5 
     6 signed main() {
     7     fib[1] = fib[2] = 1;
     8     for (int i = 3; i <= 60; i++)
     9         fib[i] = fib[i - 1] + fib[i - 2];
    10     scanf("%d", &m);
    11     for (int i = 1; i <= m; i++) {
    12         scanf("%lld%lld", &x, &y);
    13         std::set<long long> s;
    14         s.insert(x);
    15         for (int j = 60; j >= 1; j--) {
    16             if (x > fib[j])
    17                 x -= fib[j], s.insert(x);
    18             if (x == 1) {
    19                 s.insert(1);
    20                 break;
    21             }
    22         }
    23         if (s.count(y)) {
    24             printf("%lld
    ", y);
    25             continue;
    26         }
    27         for (int j = 60; j >= 1; j--) {
    28             if (y > fib[j]) {
    29                 y -= fib[j];
    30                 if (s.count(y)) {
    31                     printf("%lld
    ", y);
    32                     break;
    33                 }
    34             }
    35         }    
    36     }
    37     return 0;
    38 }
    Fibonacci


    Problem B:数颜色

    看到这题就想到了Luogu P1903 数颜色,满脑子都是莫队,我的脑子再也容不下其他的想法(

    光速码一个带修莫队,然而由于太久没写,出了很大的偏差。。。。先想了大约半小时,然后调调调,对了个拍感觉没啥问题,不过耗时太多了,已经9:50了。。。期望得分60

    然而T成40????

    GMK怒斥,块长开了$ sqrt N $,必死无疑

    猛然惊醒,带修莫队最优块长是$ N ^ {frac{2}{3}}$。。。


    带修莫队最优块长是$ N ^ {frac{2}{3}}$!!


    带修莫队最优块长是$ N ^ {frac{2}{3}}$ !!!


    写这种带根号的东西的时候多试试块长。。。20分白丢了。。。。。

     1 #include <bits/stdc++.h>
     2 
     3 const int N = 3e5 + 233;
     4 int n, m, a[N], cnt[N], blk, pos[N], ans[N], ncnt, ccnt, ch[N];
     5 struct Node {
     6     int l, r, t, c, id;
     7     friend bool operator <(Node a, Node b) {
     8         if (pos[a.l] != pos[b.l]) return pos[a.l] < pos[b.l];
     9         if (pos[a.r] != pos[b.r]) return pos[a.r] < pos[b.r];
    10         else return a.t < b.t;
    11     }
    12 } nd[N];
    13 
    14 inline int R() {
    15     int a = 0; char c = getchar();
    16     while (!isdigit(c)) c = getchar();
    17     while (isdigit(c)) a = a * 10 + c - '0', c = getchar();
    18     return a;
    19 }
    20 
    21 void Change(int t, int l, int r) {
    22     if (ch[t] + 1 == l)
    23         ++cnt[a[l - 1]], --cnt[a[l]]; 
    24     if (ch[t] == r) 
    25         ++cnt[a[r + 1]], --cnt[a[r]];
    26     std::swap(a[ch[t]], a[ch[t] + 1]);
    27 }
    28 
    29 inline void Add(int x) {cnt[x]++;}
    30 
    31 inline void Del(int x) {cnt[x]--;}
    32 
    33 signed main() {
    34     n = R(), m = R();
    35     for (int i = 1; i <= n; i++) a[i] = R();
    36     for (int i = 1, op; i <= m; i++) {
    37         op = R();
    38         if (op == 1) {
    39             int l = R(), r = R(), c = R();
    40             nd[++ncnt] = {l, r, ccnt, c, ncnt};
    41         } else {
    42             ch[++ccnt] = R();
    43         }
    44     }
    45     blk = pow(n, 0.666666);
    46     for (int i = 1; i <= n; i++)
    47         pos[i] = (i - 1) / blk + 1;
    48     std::sort(nd + 1, nd + 1 + ncnt);
    49     for (int i = 1, l = 1, r = 0, tim = 0; i <= ncnt; i++) {
    50         while (tim < nd[i].t) Change(++tim, l, r);
    51         while (tim > nd[i].t) Change(tim--, l, r);
    52         while (l < nd[i].l) Del(a[l++]);
    53         while (l > nd[i].l) Add(a[--l]);
    54         while (r < nd[i].r) Add(a[++r]);
    55         while (r > nd[i].r) Del(a[r--]);
    56         ans[nd[i].id] = cnt[nd[i].c];
    57     }
    58     for (int i = 1; i <= ncnt; i++)
    59         printf("%d
    ", ans[i]);
    60     return 0;
    61 }
    Captian Mo's Algorithm


    正解有两种,数据结构学傻了的动态开点线段树和二分我选择二分


    动态开点线段树好像空间有点问题,TKJ开了迫真内存池其实只是内存回收,我还是写二分了


    开个vector存每种颜色存在的位置,修改直接二分查见修改位置暴力改,查询仍旧二分查位置,不多谈了。不过要注意查询的时候一个lower_bound一个upper_bound。

    谨防数据结构学傻。。。。别让你的思维被那几个sqrt/log锢住。。。。

     1 #include <bits/stdc++.h>
     2 
     3 const int N = 3e5 + 5;
     4 int n, m, a[N];
     5 std::vector<int> v[N];
     6 
     7 inline int R() {
     8     int a = 0; char c = getchar();
     9     while (!isdigit(c)) c = getchar();
    10     while (isdigit(c)) a = a * 10 + c - '0', c = getchar();
    11     return a;
    12 }
    13 
    14 signed main() {
    15     n = R(), m = R();
    16     for (int i = 1; i <= n; i++) {
    17         a[i] = R();
    18         v[a[i]].push_back(i);
    19     }
    20     for (int i = 1, op; i <= m; i++) {
    21         op = R();
    22         if (op == 1) {
    23             int l = R(), r = R(), c = R();
    24             int p = std::lower_bound(v[c].begin(), v[c].end(), l) - v[c].begin();
    25             int q = std::upper_bound(v[c].begin(), v[c].end(), r) - v[c].begin();
    26             printf("%d
    ", q - p);
    27         } else {
    28             int x = R();
    29             if (a[x] != a[x + 1]) {
    30                 int p = std::lower_bound(v[a[x]].begin(),
    31                         v[a[x]].end(), x) - v[a[x]].begin();
    32                 int q = std::lower_bound(v[a[x + 1]].begin(),
    33                         v[a[x + 1]].end(), x + 1) - v[a[x + 1]].begin();
    34                 v[a[x]][p]++, v[a[x + 1]][q]--;
    35                 std::swap(a[x], a[x + 1]);
    36             }
    37         }
    38     }
    39     return 0;
    40 }
    Binary Serach

    Problem C:分组

    考试的时候时间不够了,而且读题读错了。。。。可见置顶计数器。

    首先T2时间拖太久,心态有点爆炸了,这次考试的时间安排是有问题的。。。。

    然后是读了题后我就开始想,这个团体该咋分啊,然后我就想。。。想了20min左右时间不够了,只能printf("1 ")了。。。

    考完听讲题才看见K只能等于1或2。。。。。

    少星际,多读题。。。多看看数据范围没坏处。。。。

    K=1时显然,只能是把1-n分成几个连续的区间,直接单调地扫一遍就完事了。但有一个点,就是关于如何维护冲突。一看这数据范围,枚举平方的话撑死不到5122。我们维护一个是否出现过的数组vis[],每有一个新的数就枚举幂k,看$k^2 - a_i$是否出现过。这样就把判断的复杂度降下来了。

    注意,为了得到字典序最小的答案,我们从后往前枚举,这样能使分的位置尽量考前。

     1 namespace Subtask1 {
     2     signed QAQ() {
     3         for (int i = n, j = n; i;) {
     4             for (bool gg = 0; j; j--) {
     5                 for (int k = 1; k * k - a[j] < N; k++) {
     6                     if (k * k - a[j] <= 0) continue;
     7                     if (vis[k * k - a[j]]) {gg = 1; break;}
     8                 }
     9                 if (gg) break;
    10                 vis[a[j]] = 1;
    11             }
    12             if (!j) break;
    13             brk[++m] = j;
    14             for (; i > j; i--) vis[a[i]] = 0;
    15         }
    16         printf("%d
    ", m + 1);
    17         for (int i = m; i >= 1; i--)
    18             printf("%d ", brk[i]);
    19         puts("");
    20         return 0;
    21     }
    22 }
    Subtask 1

    K=2时我们可以在每个区间放冲突兔子了。如果把冲突兔子互相连边,区间实际上形成了二分图。

    你暴力染色check肯定不行,$N^2$复杂度爆炸 然而数据太水,HZ有人这么A了

    我反正看到这玩意就想起的不是关押罪犯,而是Luogu P2024 食物链。这是一个拓展域冰茶姬的板子。

    我最开始是很懵的,gmk画图给我解了惑。我们把每只兔子拆开,冲突兔子相连,当达到什么的时候会冲突呢?就是兔子的两个点属于同一集合的时候。这个自己画图多膜膜你%你出来。

    于是我们就在Subtask1的基础上,把这玩意加进去。

     1 namespace Subtask2 {
     2     int fa[N << 1], mx;
     3     bool sp[N << 1], vis[N << 1];
     4 
     5     int get(int x) {
     6         return fa[x] == x ? x : fa[x] = get(fa[x]);
     7     }
     8 
     9     void merge(int x, int y) {
    10         x = get(x), y = get(y);
    11         fa[x] = y;
    12     }
    13 
    14     void QAQ() {
    15         for (int i = 1; i <= n; i++) mx = std::max(mx, a[i]);
    16         for (int i = 1; i <= 2 * mx; i++) fa[i] = i;
    17         for (int i = n; i >= 1; i--) {
    18             for (int j = 2; j <= 512; j++) {
    19                 if (j * j - a[i] <= 0) continue;
    20                 if (vis[j * j - a[i]]) {
    21                     merge(a[i], j * j - a[i] + mx);
    22                     merge(a[i] + mx, j * j - a[i]);
    23                 }
    24             }
    25             if (get(a[i]) == get(a[i] + mx)) {
    26                 brk[++m] = i;
    27                 for (int j = i; j <= (m == 1 ? n : brk[m - 1]); j++)
    28                     fa[a[j]] = a[j], fa[a[j] + mx] = a[j] + mx, vis[a[j]] = 0;
    29             }
    30             vis[a[i]] = 1;
    31         }
    32     }
    33 }
    Subtask2_first

    然而有一个问题,有重复兔子啊。。。当然不是所有重复兔子都要背锅,如果2倍是完全平方数就要背锅了。我们必须把她们放在两组。

    大力特判,一个背锅兔子出现两次就不能插入敌对兔子了,放不下。

    调试n年。。。。。。。。。

    详情请见计数器。

     1 namespace Subtask2 {
     2     int get(int x) {
     3         return fa[x] == x ? x : fa[x] = get(fa[x]);
     4     }
     5 
     6     void merge(int x, int y) {
     7         x = get(x), y = get(y);
     8         if (x != y) fa[x] = y;
     9     }
    10 
    11     signed QAQ() {
    12         for (int i = 2; i <= 512; i++) 
    13             if (!((i * i) & 1)) sp[(i * i) / 2] = 1;
    14         for (int i = 1; i <= n; i++) mx = std::max(mx, a[i]);
    15         for (int i = 1; i <= 2 * mx; i++) fa[i] = i;
    16         for (int i = n; i >= 1; i--) {
    17             for (int j = 2; j <= 512; j++) {
    18                 if (j * j - a[i] <= 0) continue;
    19                 if (j * j == 2 * a[i]) continue;
    20                 if (vis[j * j - a[i]]) {
    21                     if (sp[j * j - a[i]] && vis[j * j - a[i]] >= 2) {
    22                         merge(a[i], a[i] + mx);
    23                         break;
    24                     }
    25                     merge(a[i], j * j - a[i] + mx);
    26                     merge(a[i] + mx, j * j - a[i]);
    27                 }
    28             }
    29             if (sp[a[i]] && vis[a[i]]) {
    30                 if (vis[a[i]] >= 2) merge(a[i], a[i] + mx);
    31                 else for (int j = 2; j <= 512; j++) {
    32                     if (j * j - a[i] <= 0) continue;
    33                     if (j * j == 2 * a[i]) continue;
    34                     if (vis[j * j - a[i]]) {
    35                         merge(a[i], a[i] + mx);
    36                         break;
    37                     }
    38                 }
    39             }
    40             if (get(a[i]) == get(a[i] + mx)) {
    41                 brk[++m] = i;
    42                 for (int j = i; j <= (m == 1 ? n : brk[m - 1]); j++)
    43                     fa[a[j]] = a[j], fa[a[j] + mx] = a[j] + mx, vis[a[j]] = 0;
    44             }
    45             vis[a[i]]++;
    46         }
    47         printf("%d
    ", m + 1);
    48         for (int i = m; i >= 1; i--)
    49             printf("%d ", brk[i]);
    50         printf("
    ");
    51         return 0;
    52     }
    53 }
    Subtask 2_final

    完全代码:

     1 #include <bits/stdc++.h>
     2 
     3 const int N = 131072 * 2 + 233;
     4 int n, k, a[N], m, brk[N], fa[N << 1], mx, vis[N << 1];
     5 bool sp[N << 1];
     6 
     7 namespace Subtask1 {
     8     signed QAQ() {
     9         for (int i = n, j = n; i;) {
    10             for (bool gg = 0; j; j--) {
    11                 for (int k = 1; k * k - a[j] < N; k++) {
    12                     if (k * k - a[j] <= 0) continue;
    13                     if (vis[k * k - a[j]]) {gg = 1; break;}
    14                 }
    15                 if (gg) break;
    16                 vis[a[j]] = 1;
    17             }
    18             if (!j) break;
    19             brk[++m] = j;
    20             for (; i > j; i--) vis[a[i]] = 0;
    21         }
    22         printf("%d
    ", m + 1);
    23         for (int i = m; i >= 1; i--)
    24             printf("%d ", brk[i]);
    25         puts("");
    26         return 0;
    27     }
    28 }
    29 
    30 namespace Subtask2 {
    31     int get(int x) {
    32         return fa[x] == x ? x : fa[x] = get(fa[x]);
    33     }
    34 
    35     void merge(int x, int y) {
    36         x = get(x), y = get(y);
    37         if (x != y) fa[x] = y;
    38     }
    39 
    40     signed QAQ() {
    41         for (int i = 2; i <= 512; i++) 
    42             if (!((i * i) & 1)) sp[(i * i) / 2] = 1;
    43         for (int i = 1; i <= n; i++) mx = std::max(mx, a[i]);
    44         for (int i = 1; i <= 2 * mx; i++) fa[i] = i;
    45         for (int i = n; i >= 1; i--) {
    46             for (int j = 2; j <= 512; j++) {
    47                 if (j * j - a[i] <= 0) continue;
    48                 if (j * j == 2 * a[i]) continue;
    49                 if (vis[j * j - a[i]]) {
    50                     if (sp[j * j - a[i]] && vis[j * j - a[i]] >= 2) {
    51                         merge(a[i], a[i] + mx);
    52                         break;
    53                     }
    54                     merge(a[i], j * j - a[i] + mx);
    55                     merge(a[i] + mx, j * j - a[i]);
    56                 }
    57             }
    58             if (sp[a[i]] && vis[a[i]]) {
    59                 if (vis[a[i]] >= 2) merge(a[i], a[i] + mx);
    60                 else for (int j = 2; j <= 512; j++) {
    61                     if (j * j - a[i] <= 0) continue;
    62                     if (j * j == 2 * a[i]) continue;
    63                     if (vis[j * j - a[i]]) {
    64                         merge(a[i], a[i] + mx);
    65                         break;
    66                     }
    67                 }
    68             }
    69             if (get(a[i]) == get(a[i] + mx)) {
    70                 brk[++m] = i;
    71                 for (int j = i; j <= (m == 1 ? n : brk[m - 1]); j++)
    72                     fa[a[j]] = a[j], fa[a[j] + mx] = a[j] + mx, vis[a[j]] = 0;
    73             }
    74             vis[a[i]]++;
    75         }
    76         printf("%d
    ", m + 1);
    77         for (int i = m; i >= 1; i--)
    78             printf("%d ", brk[i]);
    79         printf("
    ");
    80         return 0;
    81     }
    82 }
    83 
    84 signed main() {
    85     scanf("%d%d", &n, &k);
    86     for (int i = 1; i <= n; i++) scanf("%d", a + i);
    87     if (k == 1) return Subtask1::QAQ();
    88     else return Subtask2::QAQ();
    89 }
    考试不读题,爆0两行泪
  • 相关阅读:
    day47---分组多表查询练习
    day47---数据库进阶知识(二)
    day46---数据库练习
    安全项目(癞蛤蟆病毒)
    pywin32安装步骤
    pip安装报错:error:Microsoft Visual C++ 14.0
    windows下anaconda安装
    数据库常用命令
    MySQL数据库初识
    linux安装MySQL
  • 原文地址:https://www.cnblogs.com/gekoo/p/11295839.html
Copyright © 2011-2022 走看看