• 2017ACM/ICPC Guangxi Invitational Solution


     

    A: A Math Problem

    题意:给出一个n,找出有多少个k满足k<= n

    思路: kk的增长很快,当k == 16 的时候就已经超过1e18 了,对于每一次询问,暴力一下就可以

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 typedef long long ll;
     6 
     7 ll n;
     8 
     9 inline ll qpow(ll x, ll n)
    10 {
    11     ll ans = 1;
    12     ll base = x;
    13     while (n)
    14     {
    15         if (n & 1) ans = ans * base;
    16         base = base * base;
    17         n >>= 1;
    18     }
    19     return ans;
    20 }
    21 
    22 int main()
    23 {
    24     while (scanf("%lld", &n) != EOF)
    25     {
    26         int i;
    27         for (i = 1; i <= 15; i++)
    28         {
    29             if (qpow(i, i) > n)
    30             {
    31                 i--;
    32                 break;
    33             }
    34         }
    35         if (i == 16) i--;
    36         printf("%d
    ", i);
    37     }        
    38 }
    View Code

    B:Color it

    题意:给出四种操作,

    0 清空所有点

    1 x y c  往(x, y) 处插入一个颜色为c的点

    2 x y1 y2 查询(1, y1) 到(x, y2) 这个矩形里面有多少个颜色不同的点

    3 退出程序

    思路: 很显然 操作0 相当于多组样例 操作3是退出程序 故我们只需要考虑第1种操作和第2种操作

    因为查询的范围当中x的左界是固定的,我们可以想到以y坐标轴来建线段树

    因为只有51种颜色,我们考虑建51棵线段树,然后每次保存离左边界最近的横坐标,看看那个y1 - y2 那个区间内是否存在一个x' < x

    存在的话就有这种颜色

    然后开五十棵线段树,会爆内存,但是可以想到,每次更新最多增加log(n)的点,操作数量的上限也才150000, 故可以动态开点

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define INF 0x3f3f3f3f
     6 #define N 1000100
     7 
     8 struct node
     9 {
    10     int l, r, v;
    11     inline node() 
    12     {
    13         l = 0, r = 0, v = INF;
    14     }
    15     inline node(int l, int r, int v) : l(l), r(r), v(v) {}
    16 }tree[N << 2];
    17 
    18 int root[55];
    19 int cnt, tag;
    20 
    21 inline void Init()
    22 {
    23     for (int i = 0; i <= cnt; ++i)
    24         tree[i] = node();
    25     memset(root, 0, sizeof root);
    26     cnt = 0;
    27 } 
    28 
    29 inline void update(int &id, int l, int r, int x, int y)
    30 {
    31     if (id == 0)
    32     {
    33         id = ++cnt;
    34         tree[id].v = x;
    35     }
    36     tree[id].v = min(tree[id].v, x);
    37     if (l == r) return;
    38     int mid = (l + r) >> 1;
    39     if (y <= mid) update(tree[id].l, l, mid, x, y);
    40     else update(tree[id].r, mid + 1, r, x, y);
    41 }
    42 
    43 inline void query(int id, int l, int r, int ql, int qr, int x)
    44 {
    45     if (id == 0 || tag) return;
    46     if (l >= ql && r <= qr)
    47     {
    48         if (tree[id].v <= x)
    49             tag = 1;
    50         return;
    51     }
    52     int mid = (l + r) >> 1;
    53     if (ql <= mid) query(tree[id].l, l, mid, ql, min(mid, qr), x); 
    54     if (qr > mid) query(tree[id].r, mid + 1, r, max(ql, mid + 1), qr, x);
    55 }
    56 
    57 int main()
    58 {
    59     int op, x, y1, y2, c;
    60     while (scanf("%d", &op) != EOF)
    61     {
    62         if (op == 3) return 0;
    63         if (op == 0)
    64         {
    65             Init();
    66         }
    67         if (op == 1)
    68         {
    69             scanf("%d%d%d", &x, &y1, &c);
    70             update(root[c], 1, 1000000, x, y1);
    71         }
    72         if (op == 2)
    73         {
    74             scanf("%d%d%d", &x, &y1, &y2);
    75             if (y1 > y2) swap(y1, y2);
    76             int ans = 0;
    77             for (int i = 0; i <= 50; ++i)
    78             {
    79                 tag = 0;
    80                 query(root[i], 1, 1000000, y1, y2, x);
    81                 if (tag) 
    82                 {
    83                     ans++;
    84                 }
    85             }
    86             printf("%d
    ", ans);
    87         }
    88     }    
    89     return 0;
    90 }
    View Code

    C:Counting Stars

    题意:给出一个无向图,没有重边,求有多少个"A-structure"结构。"A-structure"是指一个4个点的子图,这4个点依次连接,且有一条斜边。只要有任意一条边或一个点不同,则认为它们是不同的。

    思路:选取一条边作为斜边,统计这个斜边上有多少个三元环,记为sum,那么以这个边为斜边的"A-structure"共有(sum-1)*sum/2个。但是直接枚举每条边找环的时间复杂度在完全图下可达m^2的级别,

    这显然是不行的。枚举点x,然后枚举与x相邻的点y,这样相当于枚举了每条边,然后当x的度小于sqrt(m)时,我们可以用O(1)的时间判断y是否与x其他相邻的点组成三元环,而当x的度大于sqrt(m)时,我们

    可以枚举与y相邻的点z,用set判断x与z是否有边。因为mmin(2×105,n(n1)/2),所以度大于sqrt(m)的点不会很多,这样时间复杂度就是msqrt(m)了。 

     1 #include <iostream>
     2 #include <iomanip>
     3 #include <fstream>
     4 #include <sstream>
     5 #include <cmath>
     6 #include <cstdio>
     7 #include <cstring>
     8 #include <cctype>
     9 #include <algorithm>
    10 #include <functional>
    11 #include <numeric>
    12 #include <string>
    13 #include <set>
    14 #include <map>
    15 #include <stack>
    16 #include <vector>
    17 #include <queue>
    18 #include <deque>
    19 #include <list>
    20 using namespace std;
    21 
    22 const int N = 100005;
    23 vector<int> g[N];
    24 set<long long> p;
    25 int fa[N], f[N], du[N];
    26 int main() {
    27     int n, m, i, j, k, x, y;
    28     long long ans, sum;
    29     while (scanf("%d %d", &n, &m) != EOF) 
    30     {
    31         ans = 0; p.clear();
    32         for (i = 1; i <= n; ++i)
    33         {
    34             f[i] = fa[i] = du[i] = 0; g[i].clear();
    35         }
    36         for (i = 1; i <= m; ++i) 
    37         {
    38             scanf("%d %d", &x, &y);
    39             g[x].push_back(y);
    40             g[y].push_back(x);
    41             p.insert((long long)x*n + y);
    42             p.insert((long long)y*n + x);
    43             du[x]++; du[y]++;
    44         }
    45         for (i = 1; i <= n; ++i)
    46         {
    47             f[i] = 1; 
    48             for (j = 0; j < du[i]; ++j)    fa[g[i][j]] = i;
    49             for (j = 0; j < du[i]; ++j)
    50             {
    51                 x = g[i][j];
    52                 if (f[x] == 1)    continue;
    53                 sum = 0;
    54                 if (du[x] <= (int) sqrt(m))
    55                 {
    56                     for (k = 0; k < du[x]; ++k)
    57                         if (fa[g[x][k]] == i)    sum++;
    58                 }
    59                 else
    60                 {
    61                     for (k = 0; k < du[i]; ++k)
    62                         if (p.find((long long)x*n + g[i][k]) != p.end())    sum++;
    63                 }
    64                 ans += (sum - 1)*sum / 2;
    65             }
    66         }
    67         printf("%lld
    ",ans);
    68     }
    69     return 0;
    70 }
    View Code

    D:Covering

    题意:求用 1 * 2 和 2 * 1 的方块填充 4 * n 的矩形,求有多少方法

    思路:n很大,显然是log(n)的做法,猜测应该是矩阵快速幂递推。用搜索或者状压DP暴力出前几项,发现前几项是这样的

    1 1

    2 5

    3 11

    4 36

    5 95

    6 281

    7 781

    满足递推式 F[n] = F[n - 1] + 5 * F[n - 2] + F[n - 3] - F[n - 4];

    然后构造矩阵 矩阵快速幂一下

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define ll long long
     6 
     7 const int MOD = (int)1e9 + 7;
     8 
     9 struct node
    10 {
    11     ll a[4][4];
    12     inline node() 
    13     {
    14         memset(a, 0, sizeof a);
    15     }
    16     inline node operator * (const node& r) const
    17     {
    18         node ans = node();
    19         for (int i = 0; i < 4; ++i)
    20             for (int j = 0; j < 4; ++j)
    21                 for (int k = 0; k < 4; ++k)
    22                     ans.a[i][j] = (ans.a[i][j] + (a[i][k] * r.a[k][j] + MOD) % MOD + MOD) % MOD;
    23         return ans;
    24     }
    25 };
    26 
    27 ll arr[4][4] = 
    28 {
    29     1, 1, 0, 0, 
    30     5, 0, 1, 0,
    31     1, 0, 0, 1,
    32    -1, 0, 0, 0,
    33 };
    34 
    35 inline node qpow(ll n)
    36 {
    37     node ans = node();
    38     ans.a[0][0] = 36, ans.a[0][1] = 11, ans.a[0][2] = 5, ans.a[0][3] = 1;
    39     node base = node();
    40     for (int i = 0; i < 4; ++i)
    41         for (int j = 0; j < 4; ++j)
    42             base.a[i][j] = arr[i][j];
    43     while (n)
    44     {
    45         if (n & 1) ans = ans * base;
    46         base = base * base;
    47         n >>= 1;
    48     }
    49     return ans;
    50 }
    51 
    52 ll n;
    53 
    54 int main()
    55 {
    56     while (scanf("%lld", &n) != EOF)
    57     {
    58         if (n == 1) puts("1");
    59         else if (n == 2) puts("5");
    60         else if (n == 3) puts("11");
    61         else if (n == 4) puts("36");
    62         else
    63         {
    64             node ans = qpow(n - 4);
    65             printf("%lld
    ", ans.a[0][0]);
    66         }
    67     }
    68     return 0;
    69 }
    View Code

    E:CS Course

    题意:给出n个数,然后有q次查询,每次查询给出一个p,要求输出这n个数中,去掉第p个数的所有数分别进行按位与运算,按位异或运算,按位或运算的和

    思路:首先考虑按位异或运算,根据异或运算的性质,我们只需要先预处理出所有数的异或和,然后每次输出时异或一下第p个数就行了 因为这样第p个数就异或了两次,相当于没有异或

    再考虑按位与运算 我们也是先处理出所有数相与之后的那个和, 并且开一个数组记录一下每个二进制位上为1的数有多少, 再考虑以下几种情况

    为了方便,我们假设第p个数为A,所有数相与之后的和为B,接下来我们再按二进制位考虑

    1° 对于某一位上,B为0,并且A为0,并且所有数那一位上为1的个数为n - 1 那么我们可以知道,如果去掉A,那么剩下的数相与,那一位上肯定是1

    2° 对于某一位上,B为1,很显然,去掉A之后,肯定也会为1

    3° 对于某一位上,B为0,并且不满足第一种情况,那只能为0

    按位或运算的思考方法和按位与运算思考方法差不多,此处故不再给出。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define N 100010
     6 #define ll long long 
     7 
     8 int n, q;
     9 
    10 ll arr[N];
    11 
    12 int a[60];
    13 
    14 int main()
    15 {
    16     while (scanf("%d%d", &n, &q) != EOF)
    17     {
    18         ll Xor = 0, And, Or = 0;
    19         memset(a, 0, sizeof a);
    20         for (int i = 1; i <= n; i++)
    21         {
    22             scanf("%lld", arr + i);
    23             Xor ^= arr[i];
    24             if (i == 1) And = arr[1];
    25             else And &= arr[i];
    26             Or |= arr[i];
    27             ll tmp = arr[i];
    28             for (int j = 0; j <= 40; j++)
    29             {
    30                 a[j + 1] += (tmp & (1ll << j)) ? 1 : 0;
    31                 if ((1ll << j) > tmp) break;
    32             }    
    33         }
    34 //        for (int i = 0; i <= 40; i++) printf("%d%c", a[i], " 
    "[i == 40]);
    35 //        printf("%lld %lld %lld
    ", Xor, And, Or);
    36         int p;
    37         while (q--)
    38         {
    39             scanf("%d", &p);
    40             ll aa = Xor ^ arr[p];
    41             ll bb = 0; ll cc = 0;
    42             for (ll i = 0; i <= 40; i++)
    43             {
    44                 if ((And & (1ll << i)) == 0 && a[i + 1] == n - 1 && (arr[p] & (1ll << i)) == 0) bb += (1ll << i);
    45                 else if (And & (1ll << i)) bb += (1ll << i);
    46                 if ((Or & (1ll << i)) && a[i + 1] == 1 && (arr[p] & (1ll << i))) continue;
    47                 if ((Or & (1ll << i)) == 0) continue;
    48                 cc += (1ll << i);
    49 //                printf("%lld %lld
    ", bb, cc);    
    50             }
    51 //            cout << "bug
    ";
    52             printf("%lld %lld %lld
    ", bb, cc, aa);
    53         }
    54     }
    55     return 0;
    56 }
    View Code

    F:Destory Walls

    题意:给出国王所在的坐标,以及一些点,再给出一些边,表示两个点之间有一堵墙,然后国王想拆掉一些墙,使得所有区域连通,使得拆掉墙的数量最少以及花费最少,没给出的边就说明两个点之间没有墙

    思路:对偶图,是把面看成点,面与面之间连边,那么我们可以想到,如果给出的边关系构成的图没有环的话,那么只有一个面,也就是说所有区域都是连通的,那么我们就是想办法留下一棵树,使得边数尽量多,上面的权值和尽量大

    那就是求一棵最大生成树

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 100010
     5 #define ll long long
     6 
     7 int n, m;
     8 int pre[N];
     9 ll tot;
    10 
    11 inline int find(int x)
    12 {
    13     if (pre[x] != x)
    14         pre[x] = find(pre[x]);
    15     return pre[x];
    16 }
    17 
    18 struct Edge
    19 {
    20     int u, v; ll w;
    21     inline void scan()
    22     {
    23         scanf("%d%d%lld", &u, &v, &w);
    24         tot += w;
    25     }
    26     inline bool operator < (const Edge &r) const
    27     {
    28         return w > r.w;
    29     }
    30 }edge[N << 1];
    31 
    32 inline void Run()
    33 {
    34     while (scanf("%d%d", &n, &m) != EOF)
    35     {
    36         tot = 0;
    37         for (int i = 1, x, y; i <= n; ++i) scanf("%d%d", &x, &y), pre[i] = i;
    38         for (int i = 1; i <= m; ++i) edge[i].scan();
    39         sort(edge + 1, edge + 1 + m);
    40         int cnt = 0; ll sum = 0;
    41         for (int i = 1; i <= m; ++i)
    42         {
    43             int u = edge[i].u, v = edge[i].v;
    44             u = find(u), v = find(v);
    45             if (u == v) continue;
    46             ++cnt; sum += edge[i].w;
    47             pre[u] = v;
    48         }
    49         printf("%d %lld
    ", m - cnt, tot - sum);
    50     }
    51 
    52 }
    53 
    54 int main()
    55 {
    56     #ifdef LOCAL
    57         freopen("Test.in", "r", stdin);
    58     #endif
    59 
    60     Run();
    61 
    62     return 0;
    63 }
    View Code

    G:Duizi and Shunzi

    题意: 有n个数,两个相同的数可以组成一个对子,三个连续的数可以组成一个顺子,数字不可以重复使用,求最后可以组成多少对对子和顺子

    思路:贪心,我们优先的想法肯定是组对子,然后再是组顺子。因为组对子花的数少,组顺子花的数多。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define N 1000010
     6 #define ll long long 
     7 
     8 int n;
     9 
    10 ll arr[N];
    11 
    12 int main()
    13 {
    14     while (scanf("%d", &n) != EOF)
    15     {
    16         memset(arr, 0, sizeof arr);
    17         for (int i = 1, num; i <= n; i++)
    18         {
    19             scanf("%d", &num);
    20             arr[num]++;
    21         }
    22         ll ans = 0;
    23         for (int i = 1; i <= n; ++i)
    24         {
    25             ans += arr[i] / 2;
    26             ans += arr[i + 1] / 2;
    27             arr[i] %= 2; arr[i + 1] %= 2;
    28             if (arr[i] && arr[i + 1] && arr[i + 2]) 
    29             {
    30                 ans++;
    31                 arr[i + 2]--;
    32                 arr[i + 1]--;
    33             }
    34         }
    35         printf("%lld
    ", ans);
    36     }
    37     return 0;
    38 }
    View Code

     H - Law of Commutation

    题意:给出n和a,求有多少个b 满足 $a^b equiv b^a pmod m$

    思路:当a是奇数的时候 答案是1(我不知道为啥)

    当a是偶数的时候 我们令 $a = 2 cdot x$

    那么 $a^b = 2^b cdot x^b$

    显然 当 b > n 的时候 $a^b equiv 0 pmod m$

    那么当 b <= n 的时候 我们直接暴力

    当b > n的时候 如果存在答案 那么有 $b^a equiv 0 pmod m$

    那么 $b^a 是 m$ 的倍数 又 $m = 2 ^ n$
    所以 b 一定是 $2 ^ {frac{n}{a}}$ (向上取整,我不知道为啥) 的倍数

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 
     6 int n;
     7 ll a;
     8 
     9 inline ll qpow(ll x, ll n, ll MOD)
    10 {
    11     ll base = x;
    12     ll ans = 1;
    13     while (n)
    14     {
    15         if (n & 1) ans = ans * base % MOD;
    16         base = base * base % MOD;
    17         n >>= 1;
    18     }
    19     return ans;
    20 }
    21 
    22 inline void Run()
    23 {
    24     while (scanf("%d%lld", &n, &a) != EOF)
    25     {
    26         if (a & 1)
    27         {
    28             puts("1");
    29             continue;
    30         }
    31         ll ans = 0;
    32         ll m = 1ll << n;
    33         for (int i = 1; i <= n; ++i) if (qpow(a, i, m) == qpow(i, a, m))
    34             ++ans;
    35         ll tmp = (ll)ceil(n * 1.0 / a);
    36         tmp = 1ll << tmp;
    37         ans += (m / tmp - n / tmp);
    38         printf("%lld
    ", ans);
    39     }
    40 }
    41 
    42 int main()
    43 {
    44     #ifdef LOCAL
    45         freopen("Test.in", "r", stdin);
    46     #endif
    47 
    48     Run();
    49 
    50     return 0;
    51 }
    View Code

    I:Matching in a Tree

    留坑。

    J:Query on A Tree

    题意:给出一个树,有n个结点和q次询问,每次给出一个u和一个x,要在以结点u为根节点的子树中(包含u)中找出一个数与x异或后最大,输出异或后的数

    思路:子树,自然想到用DFS序来处理这棵树,使得所有的儿子都在连续的一段区间里面,然后用可持久化Trie树去找异或最大

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 #define N 100010
      6 #define ll long long 
      7 
      8 struct Edge
      9 {
     10     int to, nx;
     11     inline Edge() {}
     12     inline Edge(int to, int nx) : to(to), nx(nx) {}
     13 }edge[N << 1];
     14 
     15 int head[N], tot, pos, cnt;
     16 int fa[N], son[N], ord[N], ford[N];
     17 int root[N];
     18 
     19 struct node
     20 {
     21     int son[2], Count;
     22     inline node() 
     23     {
     24         memset(son, 0, sizeof son);
     25         Count = 0;
     26     }    
     27 }tree[N * 64];
     28 
     29 inline void Init()
     30 {
     31     memset(head, -1, sizeof head);
     32     pos = 0; tot = 0, cnt = 0;
     33     tree[0] = node();
     34 }
     35 
     36 inline void addedge(int u, int v)
     37 {
     38     edge[++tot] = Edge(v, head[u]); head[u] = tot;
     39 }
     40 
     41 int n, q;
     42 ll w[N];
     43 
     44 inline void DFS(int u)
     45 {
     46     ord[u] = ++pos;
     47     ford[pos] = u;
     48     for (int it = head[u]; ~it; it = edge[it].nx)
     49     {
     50         int v = edge[it].to;
     51         if (v == fa[u]) continue;
     52         DFS(v);    
     53     }
     54     son[u] = pos;
     55 }
     56 
     57 inline void Insert(ll x, int id)
     58 {
     59     bitset <32> b; b = x;    
     60     root[id] = ++cnt;
     61     tree[cnt] = tree[root[id - 1]];
     62     int poss = cnt; 
     63     for (int i = 31; i >= 0; --i)
     64     {
     65         int index = b[i];
     66         tree[++cnt] = tree[tree[poss].son[index]];
     67         tree[cnt].Count++;
     68         tree[poss].son[index] = cnt;    
     69         poss = cnt;
     70     }
     71 }
     72 
     73 inline ll Query(ll x, int l, int r)
     74 {
     75     bitset <32> b; b = x;
     76     ll ans = 0; 
     77     l = root[l], r = root[r];
     78     for (int i = 31; i >= 0; --i)
     79     {
     80         int index = b[i] ^ 1;
     81         bool flag = true;
     82         if (tree[tree[r].son[index]].Count - tree[tree[l].son[index]].Count <= 0) 
     83         {
     84             index ^= 1; 
     85             flag = false;
     86         }
     87         if (flag) ans += (1 << i);  
     88         r = tree[r].son[index]; l = tree[l].son[index];
     89     }
     90     return ans;
     91 }
     92 
     93 int main()
     94 {
     95     while (scanf("%d%d", &n, &q) != EOF)
     96     {
     97         Init();
     98         for (int i = 1; i <= n; ++i) scanf("%lld", w + i);
     99         for (int i = 1, u; i < n; ++i)
    100         {
    101             scanf("%d", &u);
    102             fa[i + 1] = u;
    103             addedge(u, i + 1);
    104         }
    105         DFS(1);
    106         for (int i = 1; i <= n; ++i)
    107         {
    108             Insert(w[ford[i]], i);
    109         }
    110         while(q--)
    111         {
    112             int u; ll x; 
    113             scanf("%d%lld",&u,&x);
    114             int l = ord[u] - 1, r = son[u];
    115             printf("%lld
    ",Query(x, l, r));
    116         }
    117     }
    118     return 0;
    119 }
    View Code
      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 
      4 typedef long long ll;
      5 
      6 const int N = 2e5 + 10;
      7 
      8 vector<int>G[N];
      9 
     10 int n, q;
     11 
     12 int ord[N], son[N], v[N], get_ord[N];
     13 int index;
     14 
     15 int trie[N * 35][2], latest[N * 35];
     16 int root[N], tot;
     17 
     18 inline void init()
     19 {
     20     memset(trie, 0, sizeof trie);
     21     memset(latest, 0, sizeof latest);
     22     memset(root, 0, sizeof root);
     23     tot = 0;
     24     index = 0;
     25     for (int i = 0; i < N; ++i)
     26     {
     27         G[i].clear();
     28     }
     29 }
     30 
     31 inline void insert(int i, int k, int p, int q)
     32 {
     33     if (k < 0)
     34     {
     35         latest[q] = i;
     36         return;
     37     }
     38     int c = v[get_ord[i]] >> k & 1;
     39     if (p) trie[q][c ^ 1] = trie[p][c ^ 1];
     40     trie[q][c] = ++tot;
     41     insert(i, k - 1, trie[p][c], trie[q][c]);
     42     latest[q] = max(latest[trie[q][0]], latest[trie[q][1]]);
     43 }
     44 
     45 inline int query(int now, int val, int k, int limit)
     46 {
     47     if (k < 0)
     48     {
     49         return v[get_ord[latest[now]]] ^ val;
     50     }
     51     int c = val >> k & 1;
     52     if (latest[trie[now][c ^ 1]] >= limit)
     53         return query(trie[now][c ^ 1], val, k - 1, limit);
     54     else
     55         return query(trie[now][c], val, k - 1, limit);
     56 }
     57 
     58 inline void dfs(int u)
     59 {
     60     ord[u] = ++index;
     61     get_ord[index] = u;
     62     for (int i = 0; i < G[u].size(); i++)
     63     {
     64         int to = G[u][i];
     65         dfs(to);
     66     }
     67     son[u] = index;
     68 }
     69 
     70 int main()
     71 {
     72     while (~scanf("%d %d", &n, &q))
     73     {
     74         init();
     75         latest[0] = -1;
     76         root[0] = ++tot;
     77         insert(0, 30, 0, root[0]);
     78         for (int i = 1; i <= n; ++i)
     79         {
     80             scanf("%d", &v[i]);
     81         }
     82         for (int i = 2, u; i <= n; ++i)
     83         {
     84             scanf("%d", &u);
     85             G[u].push_back(i);
     86         }
     87         dfs(1);
     88         for (int i = 1; i <= n; ++i)
     89         {
     90             root[i] = ++tot;
     91             insert(i, 30, root[i - 1], root[i]);
     92         }
     93         while (q--)
     94         {
     95             int u, x;
     96             scanf("%d %d", &u, &x);
     97             printf("%d
    ", query(root[son[u]], x, 30, ord[u]));
     98         }
     99     }
    100     return 0;
    101 }
    View Code

    K:Removing Mountains

    题意:

    给出一个字符串$S$,改变一个位置的字符(可以改成任意字符),使得循环节长度最小。

    输出最小循环节长度以及可改动的字符位置

    思路:

    我们考虑枚举循环节长度$x$,如果有$s[1 cdots n - x] = s[x + 1 cdots n]$,那么循环节长度为$x$,并且每个位置都可以改变成原来的字符,其实相当于原串不变

    否则我们考虑最长的$y$使得$s[1 cdots y] = s[x + 1 cdots x + y]$, 那么我们可以改变$s[y + 1]$或者$s[x + y + 1]$去判断是否能够使得$s[1 cdots n - x] = s[x + 1 cdots n]$成立,即至多改变两个位置

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0)
     4 void err() { cout << "33[39;0m" << endl; }
     5 template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); }
     6 const int N = 1e6 + 10, INF = 0x3f3f3f3f;
     7 int n; char s[N];
     8 
     9 typedef unsigned long long ull;
    10 struct Hash {
    11     static ull base[N]; 
    12     static void init() {
    13         base[0] = 1;
    14         for (int i = 1; i < N; ++i)
    15             base[i] = base[i - 1] * 131; 
    16     }
    17     ull a[N]; 
    18     inline void gao(char *s) {
    19         a[0] = 0;    
    20         for (int i = 1; s[i]; ++i) {
    21             a[i] = a[i - 1] * 131 + s[i]; 
    22         }    
    23     }
    24     ull get(int l, int r, int x, int y) {
    25         ull res = a[r] - a[l - 1] * base[r - l + 1];
    26         if (x >= l && x <= r) {
    27             res -= s[x] * base[r - x];
    28             res += s[y] * base[r - x];
    29         }
    30         return res;
    31     } 
    32 }hs;
    33 ull Hash::base[N] = {0};
    34 
    35 struct ExKMP {
    36     int Next[N];
    37     void get_Next(char *s) {
    38         int lens = strlen(s + 1), p = 1, pos;
    39         Next[1] = lens;
    40         while (p + 1 <= lens && s[p] == s[p + 1]) ++p;
    41         Next[pos = 2] = p - 1;
    42         for (int i = 3; i <= lens; ++i) {
    43             int len = Next[i - pos + 1];
    44             if (len + i < p + 1) Next[i] = len;
    45             else {
    46                 int j = max(p - i + 1, 0);
    47                 while (i + j <= lens && s[j + 1] == s[i + j]) ++j;
    48                 p = i + (Next[pos = i] = j) - 1; 
    49             }
    50         }
    51     }
    52 }exkmp;
    53 
    54 int main() {
    55     Hash::init(); 
    56     while (scanf("%d", &n) != EOF) {
    57         scanf("%s", s + 1);
    58         exkmp.get_Next(s); hs.gao(s);
    59         if (n == 1) {
    60             puts("1 1");
    61             continue;
    62         }
    63         int res = INF, num = INF; 
    64         for (int i = 2; i <= n; ++i) {
    65             int now = exkmp.Next[i];
    66             if (now == n - i + 1) {
    67                 res = i - 1;
    68                 num = n;
    69                 break;
    70             } else {
    71                 int x = 1 + now, y = i + now, len = n - i + 1; 
    72                 num = 0;
    73                 num += hs.get(1, len, x, y) == hs.get(i, n, x, y);
    74                 num += hs.get(1, len, y, x) == hs.get(i, n, y, x);
    75                 if (num) {
    76                     res = i - 1;
    77                     break;
    78                 }
    79             }
    80         }
    81         printf("%d %d
    ", res, num);
    82     }
    83     return 0;
    84 }
    View Code

    L:Yuno And lrotoridori no Sekai

    按题意暴力模拟

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define N 1000010
      5 
      6 struct Edge
      7 {
      8     int to, nx;
      9     inline Edge() {}
     10     inline Edge(int to, int nx) : to(to), nx(nx) {}
     11 }edge[N << 1];
     12 
     13 int n, q;
     14 int head[N], pos;
     15 int w[N], path[N], deep[N], fa[N], tot;
     16 int rmq[N << 1], F[N << 1], P[N << 1], cnt;
     17 vector <int> vec;
     18 
     19 struct ST
     20 {
     21     int mm[N << 1];
     22     int dp[N << 1][20];
     23     inline void init(int n)
     24     {
     25         mm[0] = -1;
     26         for (int i = 1; i <= n; ++i)
     27         {
     28             mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1];
     29             dp[i][0] = i;
     30         }
     31         for (int j = 1; j <= mm[n]; ++j)
     32         {
     33             for (int i = 1; i + (1 << j) - 1 <= n; ++i)
     34             {
     35                 dp[i][j] = rmq[dp[i][j - 1]] < rmq[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1]; 
     36             }
     37         }
     38     } 
     39     inline int query(int a, int b)
     40     {
     41         if (a > b) swap(a, b);
     42         int k = mm[b - a + 1];
     43         return rmq[dp[a][k]] <= rmq[dp[b - (1 << k) + 1][k]] ? dp[a][k] : dp[b - (1 << k) + 1][k];
     44     }
     45 }st;
     46 
     47 inline void Init()
     48 {
     49     memset(head, -1, sizeof head);
     50     pos = 0; deep[1] = 0; fa[1] = 1; 
     51 }
     52 
     53 inline void addedge(int u, int v)
     54 {
     55     edge[++pos] = Edge(v, head[u]); head[u] = pos;
     56     edge[++pos] = Edge(u, head[v]); head[v] = pos; 
     57 }
     58 
     59 inline void DFS(int u)
     60 {
     61     deep[u] = deep[fa[u]] + 1;
     62     F[++cnt] = u;
     63     rmq[cnt] = deep[u];
     64     P[u] = cnt;  
     65     for (int it = head[u]; ~it; it = edge[it].nx)
     66     {
     67         int v = edge[it].to;
     68         if (v == fa[u]) continue; 
     69         fa[v] = u; 
     70         DFS(v);
     71         F[++cnt] = u;
     72         rmq[cnt] = deep[u];
     73     }
     74 }
     75 
     76 inline void LCA_Init(int root, int node_num)
     77 {
     78     cnt = 0;
     79     DFS(root); 
     80     st.init(2 * node_num - 1); 
     81 }
     82 
     83 inline int query_lca(int u, int v)
     84 {
     85     return F[st.query(P[u], P[v])];
     86 }
     87 
     88 inline void query(int u)
     89 {
     90     vec.clear(); vec.push_back(w[u]);
     91     for (int it = head[u]; ~it; it = edge[it].nx)
     92     {
     93         int v = edge[it].to;
     94         vec.emplace_back(w[v]);
     95     }
     96     sort(vec.begin(), vec.end()); 
     97 }
     98 
     99 inline void Get(int u, int v)
    100 {
    101     int lca = query_lca(u, v);
    102     tot = 0;
    103     path[++tot] = u;
    104     while (u != lca)
    105     {
    106         u = fa[u];
    107         path[++tot] = u;
    108     }
    109     int mid = tot;
    110     while (v != lca) 
    111     {
    112         path[++tot] = v;
    113         v = fa[v];
    114     }
    115     reverse(path + 1 + mid, path + 1 + tot);
    116 }
    117 
    118 inline void add(int v)
    119 {
    120     for (int i = 1; i <= tot; ++i)
    121         w[path[i]] += v;
    122 }
    123 
    124 inline void Reverse()
    125 {
    126     for (int i = 1, j = tot; i < j; ++i, --j)
    127         swap(w[path[i]], w[path[j]]);
    128 }
    129 
    130 inline void Run()
    131 {
    132     while (scanf("%d%d", &n, &q) != EOF)
    133     {
    134         Init();
    135         for (int i = 1; i <= n; ++i) scanf("%d", w + i);
    136         for (int i = 1, u, v; i < n; ++i) 
    137         {
    138             scanf("%d%d", &u, &v);
    139             addedge(u, v);
    140         }
    141         LCA_Init(1, n); 
    142         int op, x, y, z; 
    143         while (q--)
    144         {
    145             scanf("%d%d%d", &op, &x, &y);
    146             if (op == 3)
    147             {
    148                 query(x);
    149                 while (y--) 
    150                 {
    151                     scanf("%d", &x);
    152                     printf("%d
    ", vec[x - 1]); 
    153                 }
    154             }
    155             else
    156             {
    157                 Get(x, y);
    158                 if (op == 1)
    159                     Reverse();
    160                 else
    161                 {
    162                     scanf("%d", &z);
    163                     add(z);
    164                 }
    165             }
    166         }
    167     }
    168 }
    169 
    170 int main()
    171 {
    172     #ifdef LOCAL
    173         freopen("Test.in", "r", stdin);
    174     #endif
    175 
    176     Run();
    177 
    178     return 0;
    179 }
    View Code

    赛后总结:

    • 一定要记得return 0, ll
    • 如果矩阵快速幂递推的时候,项中有负的,一定要+MOD 再 % MOD,为保险起见,输出答案的时候再% MOD
    • 如果用i来表示答案,一定要注意跳出的情况,会不会有越界跳出
    • 位运算尽量要加括号,它的优先级最低,进行移位操作的时候,如果爆int了,一定要 1ll << x
    • 两个数相与,要么为0,要么为一个> 0 的数; 而不是 要么为0,要么为1 这个想法是错误了
    • 在改动了一处之后,一定要仔细思考一下,是否有另一处需要连带改动,不要做无畏的罚时增长
    • 对于没有写过的数据结构,但是觉得可做,一定要先想清楚,不可妄想,要用别的类似的数据结构的思想来写,或者一些优秀的数据结构也可以用到题目当中来优化常数
    • 尽量不要两个人用两种思路写同一题,尽量先交流好,毕竟只有一台电脑,交流是制胜的关键
    • 一定要加强数据结构,图论,数论的练习
    • 交题前一定要测试样例,尽量测试边界或极限数据,不能过样例就急着交
  • 相关阅读:
    Scala学习笔记(四)—— 数组
    Scala学习笔记(三)—— 方法和函数
    Scala学习笔记(二)——Scala基础
    Scala学习笔记(一)
    HDFS和GFS对比学习
    HDFS原理学习
    c++日历问题
    Mapreduce学习
    c++动态规划解决数塔问题
    C++——数码管
  • 原文地址:https://www.cnblogs.com/Dup4/p/9451607.html
Copyright © 2020-2023  润新知