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
  • 相关阅读:
    AIMS 2013中的性能报告工具不能运行的解决办法
    读懂AIMS 2013中的性能分析报告
    在线研讨会网络视频讲座 方案设计利器Autodesk Infrastructure Modeler 2013
    Using New Profiling API to Analyze Performance of AIMS 2013
    Map 3D 2013 新功能和新API WebCast视频下载
    为Autodesk Infrastructure Map Server(AIMS) Mobile Viewer创建自定义控件
    ADN新开了云计算Cloud和移动计算Mobile相关技术的博客
    JavaScript修改css样式style
    文本编辑神器awk
    jquery 开发总结1
  • 原文地址:https://www.cnblogs.com/nblyz2003/p/12177652.html
Copyright © 2011-2022 走看看