zoukankan      html  css  js  c++  java
  • Comet OJ Contest #3

    好久之前打的,今晚才有空补题。不得不说这个oj的contest质量很好,比赛时间也非常友善。

    题目链接:https://cometoj.com/contest/38/problems


    A:

    温暖签到。multiset就秒了。

     1 /* basic header */
     2 #include <bits/stdc++.h>
     3 /* define */
     4 #define ll long long
     5 #define dou double
     6 #define pb emplace_back
     7 #define mp make_pair
     8 #define sot(a,b) sort(a+1,a+1+b)
     9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
    10 #define rep0(i,a,b) for(int i=a;i<b;++i)
    11 #define eps 1e-8
    12 #define int_inf 0x3f3f3f3f
    13 #define ll_inf 0x7f7f7f7f7f7f7f7f
    14 #define lson curPos<<1
    15 #define rson curPos<<1|1
    16 /* namespace */
    17 using namespace std;
    18 /* header end */
    19 
    20 const int maxn = 5e2 + 10;
    21 multiset<ll>s, a;
    22 ll sum = 0;
    23 int n, k;
    24 
    25 int main()
    26 {
    27     s.clear(); a.clear();
    28     scanf("%d%d", &n, &k);
    29     rep1(i, 1, n)
    30     {
    31         ll x; scanf("%lld", &x);
    32         for (auto i : a) s.insert(i + x);
    33         a.insert(x);
    34     }
    35     int cnt = 0, total = n * (n - 1) / 2 - k;
    36     for (auto i : s)
    37     {
    38         cnt++; if (cnt <= total) continue;
    39         sum += i;
    40     }
    41     printf("%lld
    ", sum);
    42     return 0;
    43 }
    View Code

    B:

    题⽬意思就是说通过把0变成1来将所有1变成⼀个联通块,要求最少的变换个数。

    状压dp,不妨遍历所有列,对于任意含有1的列,情况只有三种:上0下1、上1下0、上1下1,只有这三种情况才需要变化前面列的某些0来使得所有1联通。考察这三种情况。上1下1时,变换个数就是上一个含1列的编号与当前列编号之差的绝对值-1;上1下0时,需要考察上一个含1列的情况,如果上一个含1列的1与当前列的1处于同一行,变换个数就是上一个含1列的编号与当前列编号之差的绝对值-1,反之则为上一个含1列的编号与当前列编号之差的绝对值;上0下1的解法与上1下0的解法类似。

    因此,关键点在于保存上一次含1列的情况,当处理到新的含1列时考虑上述情况并更新答案即可。

     1 /* basic header */
     2 #include <bits/stdc++.h>
     3 /* define */
     4 #define ll long long
     5 #define dou double
     6 #define pb emplace_back
     7 #define mp make_pair
     8 #define sot(a,b) sort(a+1,a+1+b)
     9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
    10 #define rep0(i,a,b) for(int i=a;i<b;++i)
    11 #define eps 1e-8
    12 #define int_inf 0x3f3f3f3f
    13 #define ll_inf 0x7f7f7f7f7f7f7f7f
    14 #define lson curPos<<1
    15 #define rson curPos<<1|1
    16 /* namespace */
    17 using namespace std;
    18 /* header end */
    19 
    20 const int maxn = 1e5 + 10;
    21 int n, ans = 0, start = 0, a[2][maxn];
    22 int pre, flag = 0, lastPos; //pre: 1(up 1 down 0) 2(up 0 down 1) 3(both 1)
    23 
    24 int main()
    25 {
    26     scanf("%d", &n);
    27     for (int i = 0; i < 2; i++)
    28         for (int j = 0; j < n; j++)
    29             scanf("%d", &a[i][j]);
    30     for (int j = 0; j < n; j++)
    31     {
    32         int nowone = 0, nowtwo = 0;
    33         if (a[0][j] == 1) nowone = 1;
    34         if (a[1][j] == 1) nowtwo = 1;
    35         if (nowone || nowtwo)
    36         {
    37             if (!flag)
    38             {
    39                 lastPos = j;
    40                 if (nowone) pre = 1;
    41                 if (nowtwo) pre = 2;
    42                 if (nowone && nowtwo) pre = 3;
    43                 flag = 1;
    44                 continue;
    45             }
    46             else
    47             {
    48                 ans += j - lastPos - 1;
    49                 if (nowone && nowtwo)
    50                 {
    51                     pre = 3;
    52                 }
    53                 else if (nowone && !nowtwo)
    54                 {
    55                     if (pre == 2)
    56                     {
    57                         ans++;
    58                         pre = 3;
    59                     }
    60                     else pre = 1;
    61                 }
    62                 else if (!nowone && nowtwo)
    63                 {
    64                     if (pre == 1)
    65                     {
    66                         ans++;
    67                         pre = 3;
    68                     }
    69                     else pre = 2;
    70                 }
    71                 lastPos = j;
    72             }
    73         }
    74     }
    75     printf("%d
    ", ans);
    76     return 0;
    77 }
    View Code

    C:

    子序列中一个数的贡献是2^l,当l超过logm时无意义(因为只要考虑其是否为m的倍数)。设f[i][j][k]为前i个数选了模m为j的k个数的方案数,直接暴力,复杂度O(nmlogm)。

     1 /* basic header */
     2 #include <bits/stdc++.h>
     3 /* define */
     4 #define ll long long
     5 #define dou double
     6 #define pb emplace_back
     7 #define mp make_pair
     8 #define sot(a,b) sort(a+1,a+1+b)
     9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
    10 #define rep0(i,a,b) for(int i=a;i<b;++i)
    11 #define eps 1e-8
    12 #define int_inf 0x3f3f3f3f
    13 #define ll_inf 0x7f7f7f7f7f7f7f7f
    14 #define lson curPos<<1
    15 #define rson curPos<<1|1
    16 /* namespace */
    17 using namespace std;
    18 /* header end */
    19 
    20 const int maxn = 5e3 + 10, mod = 1e9 + 7;
    21 int n, m, a[maxn], f[15][maxn], g[maxn], t = 0, ans = 0;
    22 
    23 void add_mod(int &x, int y)
    24 {
    25     x += y;
    26     x -= (x >= mod) ? mod : 0;
    27 }
    28 
    29 int mi(int x, int y)
    30 {
    31     x -= y;
    32     x += (x < 0) ? m : 0;
    33     return x;
    34 }
    35 
    36 int main()
    37 {
    38     scanf("%d%d", &n, &m); int tmp = m; f[0][0] = 1;
    39     while (tmp % 2 == 0) t++, tmp >>= 1;   t++;
    40     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    41     for (int i = 1; i <= n; i++)
    42     {
    43         for (int j = 0; j < m; j++) g[j] = f[t][j];
    44         for (int j = 0; j < m; j++) add_mod(f[t][j], g[mi(j, a[i])]);
    45         for (int k = t; k; k--)
    46             for (int j = 0; j < m; j++)
    47                 add_mod(f[k][j], f[k - 1][mi(j, a[i])]);
    48     }
    49     for (int i = 0; i < m; i++)
    50         for (int j = 1; j <= t; j++)
    51         {
    52             int x = i;
    53             for (int k = 1; k < j; k++) x = (x << 1) % m;
    54             if (!x) add_mod(ans, f[j][i]);
    55         }
    56     printf("%d
    ", ans);
    57     return 0;
    58 }
    View Code

    D:

    一股线段树的味道。如果是单点修改,这题就是⼀个线段树维护区间线性基的题,但这⾥是区间xor。

    考虑原序列的xor差分,这样每次修改时只要修改两个位置的值即可。查询时只要特判边界,因为维护xor差分的线性基和原序列的线性基等价。总复杂度O(nlogn(logw)^2)。

      1 /* basic header */
      2 #include <bits/stdc++.h>
      3 /* define */
      4 #define ll long long
      5 #define dou double
      6 #define pb emplace_back
      7 #define mp make_pair
      8 #define sot(a,b) sort(a+1,a+1+b)
      9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
     10 #define rep0(i,a,b) for(int i=a;i<b;++i)
     11 #define eps 1e-8
     12 #define int_inf 0x3f3f3f3f
     13 #define ll_inf 0x7f7f7f7f7f7f7f7f
     14 #define lson curpos<<1
     15 #define rson curpos<<1|1
     16 /* namespace */
     17 using namespace std;
     18 /* header end */
     19 
     20 const int maxn = 5e4 + 10;
     21 int n, m, l[maxn << 2], r[maxn << 2], bit[maxn], a[maxn], mx;
     22 void addbit(int x, int y)
     23 {
     24     while (x <= n)
     25     {
     26         bit[x] ^= y;
     27         x += x & -x;
     28     }
     29 }
     30 
     31 int sumbit(int x)
     32 {
     33     int ret = 0;
     34     while (x)
     35     {
     36         ret ^= bit[x];
     37         x -= x & -x;
     38     }
     39     return ret;
     40 }
     41 
     42 struct Base
     43 {
     44     int b[32];
     45     void ins(int v)
     46     {
     47         for (int i = 30; ~i; i--)
     48             if (v & (1 << i))
     49             {
     50                 if (!b[i])
     51                 {
     52                     b[i] = v;
     53                     return;
     54                 }
     55                 else v ^= b[i];
     56             }
     57     }
     58     int work(int v)
     59     {
     60         for (int i = 30; ~i; i--) v = max(v, v ^ b[i]);
     61         return v;
     62     }
     63     void clear()
     64     {
     65         memset(b, 0, sizeof(b));
     66     }
     67 } tree[maxn << 2], e;
     68 
     69 Base merge(Base x, Base y)
     70 {
     71     for (int i = 30; ~i; i--)
     72         if (x.b[i]) y.ins(x.b[i]);
     73     return y;
     74 }
     75 
     76 void build(int curpos, int curl, int curr)
     77 {
     78     l[curpos] = curl, r[curpos] = curr;
     79     if (curl == curr)
     80     {
     81         tree[curpos].ins(a[curl]); return;
     82     }
     83     int mid = curl + curr >> 1;
     84     build(lson, curl, mid); build(rson, mid + 1, curr);
     85     tree[curpos] = merge(tree[lson], tree[rson]);
     86 }
     87 
     88 void modify(int curpos, int x, int p)
     89 {
     90     if (l[curpos] == r[curpos])
     91     {
     92         tree[curpos].clear();
     93         a[x] ^= p;
     94         addbit(x, p);
     95         tree[curpos].ins(a[x]);
     96         return;
     97     }
     98     int mid = l[curpos] + r[curpos] >> 1;
     99     if (x <= mid) modify(lson, x, p);
    100     else modify(rson, x, p);
    101     tree[curpos] = merge(tree[lson], tree[rson]);
    102 }
    103 
    104 Base query(int curpos, int curl, int curr)
    105 {
    106     if (curl > curr) return e;
    107     if (l[curpos] == curl && r[curpos] == curr) return tree[curpos];
    108     int mid = l[curpos] + r[curpos] >> 1;
    109     if (curr <= mid) return query(lson, curl, curr);
    110     else if (curl > mid) return query(rson, curl, curr);
    111     else return merge(query(lson, curl, mid), query(rson, mid + 1, curr));
    112 }
    113 
    114 int main()
    115 {
    116     scanf("%d%d", &n, &m);
    117     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    118     for (int i = n; i; i--) a[i] ^= a[i - 1], addbit(i, a[i]);
    119     build(1, 0, n);
    120     while (m--)
    121     {
    122         int op, l, r, v; scanf("%d%d%d%d", &op, &l, &r, &v);
    123         if (op == 1)
    124         {
    125             modify(1, l, v);
    126             if (r < n) modify(1, r + 1, v);
    127         }
    128         else
    129         {
    130             ll ans = max(query(1, l + 1, r).work(v), query(1, l + 1, r).work(v ^ sumbit(l)));
    131             printf("%lld
    ", ans);
    132         }
    133     }
    134     return 0;
    135 }
    View Code

    E:

    dreamoon出的神仙数学题,再见。

    F:

    题目出得非常莫队。每次把区间[l,r]扩展到[l,r+1]时需要维护a[r+1]和[l,r]这段区间的贡献。这里要利用到莫队二次离线的trick:

    莫队可以抽象为O(n*sqrt(m))次转移,每次查询一个序列中的位置对一个区间[l,r]的贡献。

    这个贡献是可以差分的,也就是说把每次转移的a[r+1]对区间[l,r]的贡献差分为a[r+1]对前缀[1,r]的贡献减去对前缀[1,l-1]的贡献。

    然后通过这个差分我们就可以发现,我们把O(n*sqrt(m))次的修改降低到了O(n)次修改,因为前缀只会扩展O(n)次。于是我们每次可以较高复杂度扩展前缀和,因为插入次数变成了O(n)次。

    然后我们离线莫队转移的时候可以做到线性空间,因为每次莫队是从一个区间转移到另一个区间。我们记pre[i]为i的前缀区间的答案,suf[i]为i的后缀区间的答案。考虑把[l1,r1]扩展到区间[l1,r2],我们可以把区间[r1,r2]的贡献差分为pre[r2]-pre[r1]-(区间[1,l1-1]对区间[r1+1,r2]的贡献)。再次差分区间[1,l1-1]对区间[r1+1,r2]的贡献为[1,l1-1]对[1,r2]的贡献减去[1,l1-1]对区间[1,r1]的贡献,每个位置开个vector保存即可。

    于是我们达成了O(n+m)的空间复杂度把莫队二次离线,现在我们要考虑怎么算这个贡献。先把贡献拆开变成两部分:[l,r]中x的倍数个数,[l,r]中x的约数个数。

    [l,r]中x的倍数个数:每次前缀加⼊⼀个数a[i]的时候,我们把a[i]的约数位置所对应的数组pre1的位置都++然后查询的时候直接查pre1[x]即可得到x的倍数个数。

    [l,r]中x的约数个数:这⾥考虑对x的约数进⾏⼀次根号分治。对于所有x⼤于sqrt(n)的约数,我们拓展前缀的时候维护,即每次把a[i]的倍数位置所对应的数组pre2的位置都++然后查询的时候直接查pre2[x]即可得到x大于sqrt的约数个数。对于所有x小于sqrt(n)的约数,我们考虑每次直接枚举区间[l,r]中1,2,...,sqrt(n)的出现次数。这里可以用fractionalcascading的trick做到O(sqrt(n)+logn)单次,线性空间。

    整个做法时间复杂度O(n*sqrt(m)),空间复杂度O(n+m)。

  • 相关阅读:
    【C++11】准备:gcc 4.9.0编译安装
    【转】C++ 虚函数表解析
    【工作总结】内存泄漏总结
    【工作总结】C++ string工具类
    工作总结
    【工作笔记】CxImage简介
    【工作笔记】没有界面程序调用ActiveX控件
    【工作笔记】npapi插件编写
    【工作笔记】VLC播放器在chrome中的调用
    Linux多任务编程之三:exec函数族及其基础实验(转)
  • 原文地址:https://www.cnblogs.com/JHSeng/p/10883373.html
Copyright © 2011-2022 走看看