zoukankan      html  css  js  c++  java
  • Codeforces Round #524 (Div. 2) Solution

    A. Petya and Origami

    Water.

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long 
     5 ll n, k;
     6 
     7 ll Get(ll x)
     8 {
     9     return (x * n) % k == 0 ? (x * n) / k : (x * n) / k + 1;
    10 }
    11 
    12 int main()
    13 {
    14     while (scanf("%lld%lld", &n, &k) != EOF)
    15     {
    16         ll res = Get(2) + Get(5) + Get(8);
    17         printf("%lld
    ", res);
    18     }
    19     return 0;
    20 }
    View Code

    B. Margarite and the best present

    Water.

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 int q, l, r;
     6 ll get(ll x)
     7 {
     8     return x * ((x & 1) ? -1 : 1);
     9 }
    10 
    11 int main()
    12 {
    13     while (scanf("%d", &q) != EOF)
    14     {
    15         for (int qq = 1; qq <= q; ++qq)
    16         {
    17             scanf("%d%d", &l, &r);
    18             if (l == r) printf("%lld
    ", get(l));
    19             else 
    20             {
    21                 ll res = 0;
    22                 if ((l & 1) == 0) res = get(l++);
    23                 if (r & 1) res += get(r--);
    24                 res += ((r - l + 1) >> 1);
    25                 printf("%lld
    ", res);
    26             }
    27         }
    28     }
    29     return 0;
    30 }
    View Code

    C. Masha and two friends

    Upsolved.

    题意:

    有一个黑白相间的棋盘,第一次选择一个矩形区域将区域内所有格子染白

    第二次选择一个矩形区域将所有格子染黑,求最后白方块个数和黑方块个数

    思路:

    考虑先求整个棋盘的黑白方块个数,再删除两块矩形的黑白方块个数,矩形交部分要加一次

    再求染色后,增加的黑块和白块个数

    考虑怎么求黑白相间的黑白方块个数,发现如果矩形有一边长为偶数,那么两种颜色数量相同

    否则,左下角是什么颜色,这个颜色的方块就多一个

    其实,只求一种颜色就好了,因为总数是不变的

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define pll pair <ll, ll>
     6 int t; ll x[4], y[4], X[2], Y[2], n, m, white, black;
     7 pll tmp;
     8 
     9 pll get(ll n, ll m, int vis)
    10 {
    11     ++n, ++m;
    12     pll res = pll(0, 0);
    13     if ((n & 1) && (m & 1)) 
    14     {
    15         res.first = res.second = ((n - 1) * m) >> 1;
    16           res.first += (m >> 1) + 1ll * (vis ^ 1);  
    17         res.second += (m >> 1) + 1ll * vis;
    18      }
    19     else
    20         res.first = res.second = (n * m) >> 1; 
    21     return res;
    22 }    
    23 
    24 ll get2(ll n, ll m) { ++n, ++m; return n * m; }
    25 
    26 int main()
    27 {
    28     scanf("%d", &t);
    29     while (t--)
    30     {
    31         scanf("%lld%lld", &n, &m); 
    32         for (int i = 0; i < 4; ++i) scanf("%lld%lld", x + i, y + i);
    33         tmp = get(n - 1, m - 1, 0); 
    34         white = tmp.first, black = tmp.second;
    35         tmp = get(y[1] - y[0], x[1] - x[0], (x[0] & 1) ^ (y[0] & 1));
    36         white -= tmp.first; black -= tmp.second;
    37         tmp = get(y[3] - y[2], x[3] - x[2], (x[2] & 1)^ (y[2] & 1)); 
    38         white -= tmp.first, black -= tmp.second; 
    39         X[0] = max(x[0], x[2]); X[1] = min(x[1], x[3]);
    40         Y[0] = max(y[0], y[2]); Y[1] = min(y[1], y[3]);
    41         if (X[0] > X[1] || Y[0] > Y[1]) 
    42         {
    43             white += get2(x[1] - x[0], y[1] - y[0]);
    44             black += get2(x[3] - x[2], y[3] - y[2]);
    45         }
    46         else
    47         {
    48             tmp = get(Y[1] - Y[0], X[1] - X[0], (X[0] & 1) ^ (Y[0] & 1));
    49             white += tmp.first;
    50             black += tmp.second;
    51             white += get2(x[1] - x[0], y[1] - y[0]) - get2(X[1] - X[0], Y[1] - Y[0]);
    52             black += get2(x[3] - x[2], y[3] - y[2]);
    53         }
    54         printf("%lld %lld
    ", white, black);
    55     }
    56     return 0;
    57 }
    View Code

    D. Olya and magical square

    Upsolved.

    题意:

    给出一个$2^n cdot 2^n 的矩形,每次可以画一个十字,使得被划区域的矩形分成四部分,新矩形边长减半$

    $求画了K刀之后,是否存在左下角矩形到右上角矩形的一条通路,使得经过的矩形边长都相等$

    $如果有,输出log2(边长)$

    思路:

    先考虑最多能画多少刀

    注意到第一次可以画一刀,第二次可以画四刀,一共可以画N次,是一个等比数列

    $frac {4^n - 1}{3}$

    暴力去逼近使得 $frac {4^n - 1}{3} <= k$

    这个时候对存在的现有矩形都多画一刀就要超过k了

    那么我们假设已经画了$tot刀,我们需要考虑怎么分配剩下的k - tot 刀$

    我们可以保持一个长度为曼哈顿距离的通路,那么这个通路以外的矩形随便画

    或者这条通路上的矩形都要画一次

    分类讨论一下是否满足即可

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 int t; ll n, k;
     6 
     7 bool ok(ll k, ll n, ll tmp)
     8 {
     9     ll tot = 0;
    10     if (k < 0) return false;
    11     for (int i = 1; i <= n; ++i) 
    12     {
    13         tot += tmp;
    14         tmp *= 4;
    15         if (tot >= k) return true;
    16     }
    17     return false;
    18 }    
    19 
    20 int ok2(ll k, ll n, ll tmp)
    21 {
    22     ll tot = 0;
    23     for (int i = 1; i <= n; ++i)
    24     {
    25         tot += tmp;
    26         tmp *= 4;
    27         if (tot == k) return i;
    28         if (tot > k) return -1;
    29     }
    30     return -1;
    31 }
    32 
    33 int main()
    34 {
    35     scanf("%d", &t);
    36     while (t--)
    37     {
    38         scanf("%lld%lld", &n, &k);
    39         ll tot = 0, tmp = 1; int i; 
    40         for (i = 1; i <= n; ++i)
    41         {
    42             tot += tmp * tmp; 
    43             tmp <<= 1;
    44             if (tot > k) 
    45             {
    46                 --i;
    47                 tmp >>= 1;
    48                 tot -= tmp * tmp;
    49                 break;
    50             }
    51             else if (tot == k) break;
    52         }
    53         if (i > n) puts("NO");
    54         else
    55         {
    56             if (i == n) printf("YES %d
    ", 0);  
    57             else
    58             {
    59                 //cerr << tot << " " << i << " " << tmp << endl;
    60                 int use;
    61                 if (ok(k - tot, n - i, tmp * tmp - tmp * 2 + 1)) printf("YES %lld
    ", n - i);
    62                 else if (ok(k - tot - (tmp * 2 - 1), n - i, tmp * tmp - tmp * 2 + 1)) printf("YES %lld
    ", n - i - 1);
    63                 else if ((use = ok2(k - tot, n - i, tmp * 2 - 1)) != -1) printf("YES %lld
    ", n - i - use);
    64                 else puts("NO");
    65             }
    66         }
    67     }
    68     return 0;
    69 }
    View Code

    E. Sonya and Matrix Beauty

    Upsolved.

    题意:

    有一个字符矩阵,对于一个子矩阵,对于每一行,可以任意改变字母顺序,使得每一行每一列都是回文串

    那么这个子矩阵就是好矩阵,求有多少个子矩阵是好矩阵

    思路:

    先考虑一行,一行在改变顺序之后是回文串,那么其拥有奇数个字母的个数$<= 1$

    再来考虑列,如果一个矩阵是好的矩阵

    那么它的第一行中每种字母的个数和最后一行中要相同,第二行要和倒数第二行相同

    注意到这和找回文串的思路很像

    可以套用Manacher 算法的思路,$O(26n)处理$

    再加上对于行的枚举

    总的复杂度为$O(26n^3)$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 600
     6 int n, m;
     7 char s[N][N];
     8 int cnt[N][30];
     9 int Mp[N];
    10 
    11 bool okone(int x)
    12 {
    13     int res = 0;
    14     for (int i = 0; i < 26; ++i) res += cnt[x][i] & 1;
    15     return res <= 1;
    16 }
    17 
    18 bool ok(int x, int y)
    19 {
    20     for (int i = 0; i < 26; ++i) if (cnt[x][i] != cnt[y][i])
    21         return false;
    22     return true;
    23 }
    24 
    25 int main()
    26 {
    27     while (scanf("%d%d", &n, &m) != EOF)
    28     {
    29         n <<= 1; 
    30         for (int i = 1; i <= n; i += 2) scanf("%s", s[i] + 1); 
    31         ll res = 0;
    32         for (int l = 1; l <= m; ++l)
    33         {
    34             memset(cnt, 0, sizeof cnt);
    35             for (int r = l; r <= m; ++r)
    36             {
    37                 memset(Mp, 0, sizeof Mp);   
    38                 for (int i = 1; i <= n; i += 2) ++cnt[i][s[i][r] - 'a'];
    39                 int Max = 0, pos = -1; 
    40                 for (int i = 1; i <= n; ++i)
    41                 {
    42                     if (!okone(i)) 
    43                     {
    44                         Mp[i] = 0;
    45                         continue;
    46                     }
    47                     if (Max > i) Mp[i] = min(Mp[2 * pos - i], Max - i);
    48                     else Mp[i] = 1;
    49                     while (i >= Mp[i] && i + Mp[i] <= n && okone(i + Mp[i]) && okone(i - Mp[i]) && ok(i + Mp[i], i - Mp[i]))
    50                     {     
    51                         ++Mp[i];
    52                     }
    53                     if (i + Mp[i] > Max)
    54                     {
    55                         Max = i + Mp[i];
    56                         pos = i; 
    57                     }
    58                     res += Mp[i] / 2;
    59                 }
    60             }
    61         }
    62         printf("%lld
    ", res);
    63     }
    64     return 0;
    65 }
    View Code

    F. Katya and Segments Sets

    Upsolved.

    题意:

    有n个集合,每个集合有若干个线段,每次询问一段连续的集合中,这些集合是否都有至少一条线段被$[l, r] 包含$

    思路:

    先考虑暴力,我们可以暴力枚举每个集合,所有$y <= r 中对应的x 的最大值是否 >= l$

    然后考虑数据结构优化

    先按r排序之后,再插入可持久化线段树之中。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 100010
     5 #define M 300010
     6 #define INF 0x3f3f3f3f
     7 int n, q, m, k, brr[M << 1];
     8 struct qnode
     9 {
    10     int l, r, p; 
    11     void scan() 
    12     {
    13         scanf("%d%d%d", &l, &r, &p);
    14         brr[++m] = r; 
    15     }
    16     bool operator < (const qnode &other) const
    17     {
    18         return r < other.r; 
    19     }
    20 }qarr[M];
    21 
    22 int GetHash(int x) { return lower_bound(brr + 1, brr + 1 + m, x) - brr; }
    23 void Hash()
    24 {
    25     sort(brr + 1, brr + 1 + m);
    26     m = unique(brr + 1, brr + 1 + m) - brr - 1;
    27     for (int i = 1; i <= k; ++i)
    28         qarr[i].r = GetHash(qarr[i].r);
    29 }
    30 
    31 namespace SEG
    32 {
    33     int T[M << 1], cnt;
    34     struct node
    35     {
    36         int ls, rs, Min; 
    37     }a[M * 50];  
    38     void build(int &now, int l, int r)
    39     {
    40         now = ++cnt; 
    41         a[now].Min = 0;     
    42         if (l == r) return;
    43         int mid = (l + r) >> 1;
    44         build(a[now].ls, l, mid);
    45         build(a[now].rs, mid + 1, r);
    46     }
    47     void update(int &now, int pre, int l, int r, int pos, int val)
    48     {
    49         now = ++cnt; 
    50         a[now] = a[pre];
    51         if (l == r)
    52         {
    53             a[now].Min = max(a[now].Min, val);  
    54             return;
    55         }
    56         int mid = (l + r) >> 1;
    57         if (pos <= mid) update(a[now].ls, a[pre].ls, l, mid, pos, val);
    58         else update(a[now].rs, a[pre].rs, mid + 1, r, pos, val);
    59         a[now].Min = min(a[a[now].ls].Min, a[a[now].rs].Min);
    60     }
    61     int query(int now, int l, int r, int ql, int qr)
    62     {
    63         if (l >= ql && r <= qr) return a[now].Min;
    64         int mid = (l + r) >> 1;
    65         int res = INF; 
    66         if (ql <= mid) res = min(res, query(a[now].ls, l, mid, ql, qr));
    67         if (qr > mid) res = min(res, query(a[now].rs, mid + 1, r, ql, qr));      
    68         return res;
    69     }
    70 }
    71 
    72 int main()
    73 {
    74     while (scanf("%d%d%d", &n, &q, &k) != EOF)
    75     {
    76         for (int i = 1; i <= k; ++i) qarr[i].scan(); Hash();
    77         sort(qarr + 1, qarr + 1 + k);
    78         SEG::build(SEG::T[0], 1, n);   
    79         for (int i = 1; i <= k; ++i) 
    80         {
    81             if (SEG::T[qarr[i].r] == 0) SEG::T[qarr[i].r] = SEG::T[qarr[i].r - 1];
    82             SEG::update(SEG::T[qarr[i].r], SEG::T[qarr[i].r], 1, n, qarr[i].p, qarr[i].l);    
    83         }
    84         for (int qq = 1, a, b, x, y; qq <= q; ++qq)
    85         {
    86             scanf("%d%d%d%d", &a, &b, &x, &y);
    87             y = upper_bound(brr + 1, brr + 1 + m, y) - brr - 1; 
    88             int tmp = SEG::query(SEG::T[y], 1, n, a, b);
    89             if (tmp >= x) puts("yes"); 
    90             else puts("no");
    91             if (qq == q) return 0;
    92             fflush(stdout);  
    93         }
    94     }
    95     return 0;
    96 }
    View Code
  • 相关阅读:
    Perl的Open函数
    较详细的介绍JNI
    Java多线程单元测试
    sleep函数的简单原理
    Struts与Servlet的冲突
    Ant学习记录
    JDK转码工具
    Throwable
    Entity Framework系列文章导航
    多核时代 .NET Framework 4 中的并行编程1概述
  • 原文地址:https://www.cnblogs.com/Dup4/p/10034250.html
Copyright © 2011-2022 走看看