zoukankan      html  css  js  c++  java
  • Codeforces Round #609 (Div. 2)前五题题解

    Codeforces Round #609 (Div. 2)前五题题解

    补题补题……

    C题写挂了好几个次,最后一题看了好久题解才懂……我太迟钝了……

    然后因为longlong调了半个小时……

    A.Equation

    题目大意:有一个数字n,让你给出任意两个合数a,b满足a - b = n。

    我们知道大于2的偶数都是合数,那么如果n为奇数,只要n加上一个奇数合数一定也为合数,如果n为偶数,那么n加上一个偶数合数也一定为合数。

    因为只求任意一组,就直接选择4,9,若为奇数输出 9+n 和9,偶数输出 4+n 和4。

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <vector>
     6 #define rep(x, l, r) for(int x = l; x <= r; x++)
     7 #define repd(x, r, l) for(int x = r; x >= l; x--)
     8 #define clr(x, y) memset(x, y, sizeof(x))
     9 #define all(x) x.begin(), x.end()
    10 #define pb push_back
    11 #define mp make_pair
    12 #define MAXN
    13 #define fi first
    14 #define se second
    15 #define SZ(x) ((int)x.size())
    16 using namespace std;
    17 typedef long long ll;
    18 typedef vector<int> vi;
    19 typedef pair<int, int> pii;
    20 const int INF = 1 << 30;
    21 const int p = 1000000009;
    22 int lowbit(int x){ return x & (-x);}
    23 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;}
    24 
    25 int main(){
    26     int n;
    27     scanf("%d", &n);
    28     if(n % 2) printf("%d %d
    ", n + 9, 9);
    29     else printf("%d %d
    ", n + 4, 4);
    30     return 0;
    31 }
    View Code

    B.Modulo Equality

    题目大意:有两个长为n的数列a和b,现在让你给a中每个数加上一个数x并对m取,并重新排列,使得两数列相同。求最小的x。

    很明显x一定是在 (a1 - bi + m) mod m 中的一个数,我们只要枚举这个数,判断和数列b是否相同即可。

    n最大只有2000,为了方便(我比较懒),判断相同时可以直接将a重新排序后判断,不会超时。

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <vector>
     6 #define rep(x, l, r) for(int x = l; x <= r; x++)
     7 #define repd(x, r, l) for(int x = r; x >= l; x--)
     8 #define clr(x, y) memset(x, y, sizeof(x))
     9 #define all(x) x.begin(), x.end()
    10 #define pb push_back
    11 #define mp make_pair
    12 #define MAXN 2005
    13 #define fi first
    14 #define se second
    15 #define SZ(x) ((int)x.size())
    16 using namespace std;
    17 typedef long long ll;
    18 typedef vector<int> vi;
    19 typedef pair<int, int> pii;
    20 const int INF = 1 << 30;
    21 const int p = 1000000009;
    22 int lowbit(int x){ return x & (-x);}
    23 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;}
    24 
    25 int a[MAXN], b[MAXN], c[MAXN];
    26 
    27 int main(){
    28     int n, m;
    29     scanf("%d%d", &n, &m);
    30     rep(i, 1, n) scanf("%d", &a[i]);
    31     rep(i, 1, n) scanf("%d", &b[i]);
    32     sort(a + 1, a + n + 1);
    33     sort(b + 1, b + n + 1);
    34     int ans = INF;
    35     rep(i, 1, n){
    36         int res = (b[1] - a[i] + m) % m;
    37         rep(j, 1, n) c[j] = (a[j] + res) % m;
    38         sort(c + 1, c + n + 1);
    39         bool flag = 1;
    40         rep(j, 1, n)
    41             if(c[j] != b[j]){
    42                 flag = 0;
    43                 break;
    44             }
    45         if(flag) ans = min(ans, res);
    46     }
    47     printf("%d
    ", ans);
    48     return 0;
    49 }
    View Code

    C.Long Beautiful Integer

    题目大意:给你一个数字x,以及正整数k,求一个大于等于x的最小数字y并满足 yi = yi + k (1 <= i <= n - k) 。n为x的长度,n小于等于500.

    这一题hack数据还真多,197组……

    首先可以发现,数字y的长度一定是等于x的长度的,因为全为9的数字一定满足条件。

    对于 yi = yi + k 这个式子,我们发现,对于所有位置i对k取模结果相同的,该位上的数字也一定是相同的。

    那我们只要枚举最后前k位数字即可,为了让数字尽量小,我们让y的每一位和x一样大,然后判断此时y和x的大小。

    若y大于等于x,那么y就是答案。若y小于x,只需要在第k位加上1即可。

    注意:需要进位!!!

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <vector>
     6 #define rep(x, l, r) for(int x = l; x <= r; x++)
     7 #define repd(x, r, l) for(int x = r; x >= l; x--)
     8 #define clr(x, y) memset(x, y, sizeof(x))
     9 #define all(x) x.begin(), x.end()
    10 #define pb push_back
    11 #define mp make_pair
    12 #define MAXN 200005
    13 #define fi first
    14 #define se second
    15 #define SZ(x) ((int)x.size())
    16 using namespace std;
    17 typedef long long ll;
    18 typedef vector<int> vi;
    19 typedef pair<int, int> pii;
    20 const int INF = 1 << 30;
    21 const int p = 1000000009;
    22 int lowbit(int x){ return x & (-x);}
    23 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;}
    24 
    25 int num[MAXN], ans[MAXN];
    26 char st[MAXN];
    27 
    28 int main(){
    29     int n, m;
    30     scanf("%d%d", &n, &m);
    31     scanf("%s", st);
    32     int maxx = 0;
    33     rep(i, 1, n){
    34         num[i] = st[i - 1] - '0';
    35         maxx = max(maxx, num[i]);
    36     }
    37     int minx = INF, miny = INF;
    38     rep(i, 1, m){
    39         ans[i] = num[i];
    40         for(int j = i ; j <= n; j += m){
    41             if(ans[i] < num[j]) minx = min(minx, j);
    42             if(ans[i] > num[j]) miny = min(miny, j);
    43         }
    44     }
    45     if(miny > minx){
    46         ans[m] = num[m] + 1;
    47         for(int x = m; x > 0 && ans[x] == 10; x--){
    48             ans[x] = 0;
    49             ans[x - 1]++;
    50         }
    51     }
    52     printf("%d
    ", n);
    53     rep(i, 1, n) printf("%d", ans[(i - 1) % m + 1]);
    54     puts("");
    55     return 0;
    56 }
    View Code

    D.Domino for Young

    题目大意:有一个不规则的网格长为n,第i列有 ai ,现在用1×2的骨牌覆盖它,求最多能放多少个骨牌。

    这题是我人生第一道秒掉的D题!!!

    一看题目,这不是《组合数学》第一章的例题嘛,虽然有点差别,但是思路基本一模一样。

    先讲一下组合那道题,就是说有一个n×m的网格(n和m为偶数),将它的左上角和右下角两个格子去掉,证明用1×2的骨牌覆盖它,没有一种方法能将它完美覆盖。

    这道题目就是0,1染色,对相邻的节点染上不同的颜色,如图所示。

     

    每一个骨牌只能覆盖一个0和一个1,而这张图中一共有12个1和10个0,不合。

    那么回到这一题,我们也可以将这个网格进行黑白染色,每一个骨牌也是只能覆盖一个0和一个1,那么在最优的覆盖方案中,覆盖完了0和1中较少的。答案就是0的个数和1的个数的最小值。

    另外统计0,1个数就不多说了,详见代码。

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <vector>
     6 #define rep(x, l, r) for(int x = l; x <= r; x++)
     7 #define repd(x, r, l) for(int x = r; x >= l; x--)
     8 #define clr(x, y) memset(x, y, sizeof(x))
     9 #define all(x) x.begin(), x.end()
    10 #define pb push_back
    11 #define mp make_pair
    12 #define MAXN 200005
    13 #define fi first
    14 #define se second
    15 #define SZ(x) ((int)x.size())
    16 using namespace std;
    17 typedef long long ll;
    18 typedef vector<int> vi;
    19 typedef pair<int, int> pii;
    20 const int INF = 1 << 30;
    21 const int p = 1000000009;
    22 int lowbit(int x){ return x & (-x);}
    23 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;}
    24 
    25 int num[MAXN], ans[MAXN];
    26 char st[MAXN];
    27 
    28 int main(){
    29     int n, m;
    30     scanf("%d%d", &n, &m);
    31     scanf("%s", st);
    32     int maxx = 0;
    33     rep(i, 1, n){
    34         num[i] = st[i - 1] - '0';
    35         maxx = max(maxx, num[i]);
    36     }
    37     int minx = INF, miny = INF;
    38     rep(i, 1, m){
    39         ans[i] = num[i];
    40         for(int j = i ; j <= n; j += m){
    41             if(ans[i] < num[j]) minx = min(minx, j);
    42             if(ans[i] > num[j]) miny = min(miny, j);
    43         }
    44     }
    45     if(miny > minx){
    46         ans[m] = num[m] + 1;
    47         for(int x = m; x > 0 && ans[x] == 10; x--){
    48             ans[x] = 0;
    49             ans[x - 1]++;
    50         }
    51     }
    52     printf("%d
    ", n);
    53     rep(i, 1, n) printf("%d", ans[(i - 1) % m + 1]);
    54     puts("");
    55     return 0;
    56 }
    View Code

    E.K Integers

    题目大意:有一数列p,长度为n。求最少的交换两个相邻数字的操作,使得数列p中存在连续子序列1,2,..., i 。其中i为1,2,..., n 。

    这题大概一看就和逆序对有关,因为这个交换相邻操作和冒泡排序一模一样,而冒泡需要的操作就是逆序对的个数。

    不难得出,当 i = n 时,答案就是逆序对个数。

    对于其它的 i 来说,我们也可以得到这样一个贪心思想,先将1..i 放到一起,然后再将它们变成有序的。

    变成有序的需要的操作很显然也可以按照 i = n 来做,但是将1..i 要放到哪里去呢?

    根据初中学习的零点分段法,不知道的可以去看百度百科(传送门)了解一下。

    最后将它们移到1..n在原数列中的中间一个位置(为了方便,后文用 mid 表示),一定是最优的,这可以用二分查找来实现。

    至于它们需要移动多少呢?这要分成左右两段来算。

    首先 mid 左边的全部移到中点,我们假设它们一共有 x 个,那么它们分别会被移到 mid - x , mid - x + 1 ,..., mid - 1 。需要移动的操作个数分别要减去它们在数列中的位置,总答案就是要减去它们的总和 sum ,这可以用线段树或树状数组维护。得出以下的式子。

    ans = mid - x + mid - x + 1 + ... + mid - 1 - sum = mid  x - sum - x • (x + 1) / 2;

    注意,在代码中为了方便x包含了在 mid 点上的点,所以变成了 mid • x - sum - x • (x - 1) / 2

    另外在右边也是差不多,得出式子为 ans = sum - mid • x - x • (x + 1) / 2

    代码中还有以下几个注意点:
    1.其实当 i = n 的时候也是可以用上一个式子算的,后面两个值都为0,你可以手算一下。

    2.需要两个树状数组,一个维护前缀和(当然也可以用归并排序并加一些记录,但是比较长),一个维护上述的 sum

    3.要开longlong!要开longlong!!要开longlong!!!重要的事情说三遍。

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <vector>
     6 #define rep(x, l, r) for(int x = l; x <= r; x++)
     7 #define repd(x, r, l) for(int x = r; x >= l; x--)
     8 #define clr(x, y) memset(x, y, sizeof(x))
     9 #define all(x) x.begin(), x.end()
    10 #define pb push_back
    11 #define mp make_pair
    12 #define MAXN 200005
    13 #define fi first
    14 #define se second
    15 #define SZ(x) ((int)x.size())
    16 using namespace std;
    17 typedef long long ll;
    18 typedef vector<int> vi;
    19 typedef pair<int, int> pii;
    20 const int INF = 1 << 30;
    21 const int p = 1000000009;
    22 int lowbit(int x){ return x & (-x);}
    23 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;}
    24 
    25 int n;
    26 int a[MAXN], pos[MAXN];
    27 ll tree0[MAXN], tree1[MAXN];
    28 
    29 void update0(int x, int y){
    30     for(int i = x; i <= n; i += lowbit(i)) tree0[i] += y;
    31 }
    32 
    33 void update1(int x, int y){
    34     for(int i = x; i <= n; i += lowbit(i)) tree1[i] += y;
    35 }
    36 
    37 ll query0(int x){
    38     ll res = 0;
    39     for(int i = x; i > 0; i -= lowbit(i)) res += tree0[i];
    40     return res;
    41 }
    42 
    43 ll query1(int x){
    44     ll res = 0;
    45     for(int i = x; i > 0; i -= lowbit(i)) res += tree1[i];
    46     return res;
    47 }
    48 
    49 int main(){
    50     scanf("%d", &n);
    51     rep(i, 1, n){
    52         scanf("%d", &a[i]);
    53         pos[a[i]] = i;
    54     }
    55     ll res0 = 0;
    56     rep(i, 1, n){
    57         res0 += i - 1 - query0(pos[i]);
    58         update0(pos[i], 1);
    59         update1(pos[i], pos[i]);
    60         int l = 1, r = n, s;
    61         while(l <= r){
    62             int mid = (l + r) >> 1;
    63             if(query0(mid - 1) * 2 <= i){
    64                 s = mid;
    65                 l = mid + 1;
    66             }
    67             else r = mid - 1;
    68         }
    69         ll left_sum0 = query0(s), left_sum1 = query1(s);
    70         ll res1 = left_sum0 * s - left_sum1 - left_sum0 * (left_sum0 - 1) / 2;
    71         ll right_sum0 = i - left_sum0, right_sum1 = query1(n) - left_sum1;
    72         res1 += right_sum1 - right_sum0 * s - right_sum0 * (right_sum0 + 1) / 2;
    73         printf("%lld ", res0 + res1);
    74     }
    75     puts("");
    76     return 0;
    77 }
    View Code
  • 相关阅读:
    jackson自动将东八区时间转成标准时间
    开发项目和所用时间 感想
    自我介绍
    后缀数组模板
    lucas模板
    后缀数组da3模板
    cf#366....
    第1月2周1天
    第1月2周2天
    第1月1周1天
  • 原文地址:https://www.cnblogs.com/nblyz2003/p/12177652.html
Copyright © 2011-2022 走看看