zoukankan      html  css  js  c++  java
  • Codeforces Round #197 (Div. 2) (A、B、C、D、E五题合集)

    A. Helpful Maths

    题目大意

    给一个连加计算式,只包含数字 1、2、3,要求重新排序,使得连加的数字从小到大

    做法分析

    把所有的数字记录下来,从小到大排序输出即可

    参考代码

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 
     8 const int N=100005;
     9 
    10 char buff[1000];
    11 int A[1000], n;
    12 
    13 int main() {
    14     scanf("%s", buff);
    15     n=0;
    16     for(int i=0; buff[i]; i+=2) A[n++]=buff[i]-'0';
    17     sort(A, A+n);
    18     printf("%d", A[0]);
    19     for(int i=1; i<n; i++) printf("+%d", A[i]);
    20     printf("
    ");
    21     return 0;
    22 }
    A

    B. Xenia and Ringroad

    题目大意

    昨晚眼睛盯着屏幕仔仔细细的看了四遍题意,硬是没看懂...下面是我猜的题意,不知道对不对,反正按照这个题意写的代码过了

    有 n 个房子编号 1 到 n 按照顺时针围成一个圈,相邻两个房子之间的距离是 1,有 m 个任务编号 1 到 m,每个任务为 i 为到达相应的房子中去,问顺序的(从 1 号任务开始完成到 m 号任务)完成这些任务最少需要走多短的路程

    做法分析

    模拟题,直接模拟就行

    参考代码

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 
     8 typedef long long LL;
     9 const int N=100005;
    10 
    11 int n, m;
    12 LL A[N];
    13 
    14 int main() {
    15     scanf("%d%d", &n, &m);
    16     for(int i=1; i<=m; i++) {
    17         scanf("%I64d", &A[i]);
    18         A[i]--;
    19     }
    20     LL last=0, ans=0;
    21     for(int i=1; i<=m; i++) {
    22         if(A[i]>=last) ans+=A[i]-last, last=A[i];
    23         else ans+=n-last+A[i], last=A[i];
    24     }
    25     printf("%I64d
    ", ans);
    26     return 0;
    27 }
    B

    C. Xenia and Weights

    题目大意

    有 10 个重量分别为 1 到 10 的砝码可用,以及一个天平,现在往天平上添加砝码,添加的规则如下:

      1. 第 i 次添加到左边的盘中,那么第 i+1 添加到右边的盘中

      2. 第 i 次添加的砝码的重量不等于第 i+1 次添加的砝码的重量

      3. 往一个盘中添加完砝码之后,要求这个盘中的所有砝码的重量严格大于另一个盘中砝码的重量

    给你一些可用的砝码,以及添加砝码的次数 m(1 ≤ m ≤ 1000),问是否存在这样一个砝码添加序列,存在子的话输出这个序列

    做法分析

    动态规划,定义状态:f[i][cur][mor] 表示第 i 次添加的砝码重量是 cur,添加完之后当前盘比另一盘重 mor 的状态是否可达,由于 m 最大为 1000,砝码重量最大为 10,所以状态的数量为 10^5,状态的转移为 10,时间复杂度为 10^6

    初值:f[0][i][i]=1 表示第 0 次添加重量为 i 的砝码,添加完之后肯定比另一个空盘多 i,其他状态为 0

    转移:f[i][cur][mor] 可以推出 f[i+1][nxt][nxt-mor],这里要求 cur!=nxt 且 nxt-mor>0

    终值:f[m-1][i][j] 只要有一个状态可达,序列存在,往回递归的找解,否则不存在

    参考代码

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 
     5 using namespace std;
     6 
     7 const int N=2006;
     8 
     9 bool f[N][11][11];
    10 char buff[111];
    11 int n;
    12 
    13 void PRINT(int dep, int cho, int mor) {
    14     int pre=-1;
    15     for(int i=1; i<=10 && pre==-1; i++)
    16         if(f[dep-1][i][cho-mor] && i!=cho) pre=i;
    17     if(dep==1) printf("%d", pre);
    18     else PRINT(dep-1, pre, cho-mor);
    19     printf(" %d", cho);
    20 }
    21 
    22 int main() {
    23     scanf("%s%d", buff, &n);
    24     memset(f, 0, sizeof f);
    25     for(int i=1; i<=10; i++) if(buff[i-1]=='1') f[0][i][i]=1;
    26     for(int i=0; i<n; i++) {
    27         for(int j=1; j<=10; j++) {
    28             for(int k=1; k<=10; k++) {
    29                 if(!f[i][j][k]) continue;
    30                 for(int nxt=1; nxt<=10; nxt++) {
    31                     if(buff[nxt-1]!='1') continue;
    32                     if(nxt-k<=0) continue;
    33                     if(nxt==j) continue;
    34                     f[i+1][nxt][nxt-k]=1;
    35                 }
    36             }
    37         }
    38     }
    39     int id1=-1, id2=-1;
    40     for(int i=1; i<=10 && id1==-1; i++)
    41         for(int j=1; j<=10 && id1==-1; j++) {
    42             if(f[n-1][i][j]) {
    43                 id1=i, id2=j;
    44                 break;
    45             }
    46         }
    47     if(id1==-1) {
    48         printf("NO
    ");
    49         return 0;
    50     }
    51     printf("YES
    ");
    52     if(n==1) printf("%d
    ", id1);
    53     else PRINT(n-1, id1, id2), printf("
    ");
    54     return 0;
    55 }
    C

    D. Xenia and Bit Operations

    题目大意

    给一个长度为 2^n 的数组,现在有 n 个操作,把这个数组变成一个数:

      1. 如果 i%2==1 那么,把第 1 个和第 2 个按位取或得到新数,把第 3 个和第 4 个按位取或得到新数...

      2. 如果 i%2==0 那么,把第 1 个和第 2 个按位异或得到新数,把第 3 个和第 4 个按位异或得到新数...

    现在给了 m 个询问,每个询问先把第 p 个位置的值改为 q,然后输出按照上面操作得到的数

    数据规模:1 ≤ n ≤ 17, 1 ≤ m ≤ 105

    做法分析

    典型的线段树水题,每个节点保存如下信息

      1. s t 这个节点表示的区间

      2. val 这个节点表示的区间按照要求的操作所得到的数

      3. dep 这个节点的层号

    每次 pushup 的时候根据层号 pushup:

      1. 层号为奇数 fa.val=L.val 按位或 R.val

      2. 层号为偶数 fa.val=L.val 按位异或 R.val

    线段树有 3 个函数:

      1. build 建树

      2. update 将某个位置的值修改

      3. pushup 由儿子节点的 val 计算父亲节点的 val

    参考代码

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 
     5 using namespace std;
     6 
     7 const int N=200006;
     8 
     9 int n, m, A[N];
    10 
    11 struct Segment_Tree {
    12     struct Node {
    13         int s, t, dep, val;
    14         void init(int L, int R, int a) {
    15             s=L, t=R, dep=a, val=A[L];
    16         }
    17     } T[N<<2];
    18 
    19     void pushUp(Node &fa, Node &L, Node &R) {
    20         if(fa.dep&1) fa.val=L.val|R.val;
    21         else fa.val=L.val^R.val;
    22     }
    23 
    24     void build(int id, int dep, int L, int R) {
    25         T[id].init(L, R, dep);
    26         if(L==R) return;
    27         int mid=(L+R)>>1;
    28         build(id<<1, dep-1, L, mid);
    29         build(id<<1|1, dep-1, mid+1, R);
    30         pushUp(T[id], T[id<<1], T[id<<1|1]);
    31     }
    32 
    33     void update(int id, int pos, int val) {
    34         if(T[id].s==T[id].t) {
    35             T[id].val=val;
    36             return;
    37         }
    38         int mid=(T[id].s+T[id].t)>>1;
    39         if(pos<=mid) update(id<<1, pos, val);
    40         else update(id<<1|1, pos, val);
    41         pushUp(T[id], T[id<<1], T[id<<1|1]);
    42     }
    43 } tree;
    44 
    45 int main() {
    46 //    freopen("in", "r", stdin);
    47     scanf("%d%d", &n, &m);
    48     int old=n;
    49     n=(1<<n);
    50     for(int i=1; i<=n; i++) scanf("%d", &A[i]);
    51     tree.build(1, old, 1, n);
    52     for(int i=0, p, q; i<m; i++) {
    53         scanf("%d%d", &p, &q);
    54         tree.update(1, p, q);
    55         printf("%d
    ", tree.T[1].val);
    56     }
    57     return 0;
    58 }
    D

    E. Three Swaps

    题目大意

    给一个序列,初始时为:1、2、3、4、...、n

    现在每次操作翻转一个区间的所有数,最多翻转三次,会得到一个新的序列

    现在给你新的那个序列,要求你给出一个合法的翻转操作指令,使得从最初的序列变成给你的序列

    题目保证存在解,且最多不超过 3 次翻转

    做法分析

    考虑从当前的序列翻回去

    假设 [1, L-1], [R+1, n] 这两个区间是排好序的,即:A[i]=i,对于 i 属于这两个区间

    [L, R] 这个区间是乱序的,即 A[L]!=L 且 A[R]!=R

    另 A[Lpos]=L,A[Rpos]=R

    那么,每次翻转的时候,有两种选择:

      1. 翻转 [L, Lpos]

      2. 翻转 [Rpos, R]

    这样做必然能够将序列翻转回去,直接 DFS 即可,最后输出解的时候需要注意:人家问的是怎么翻转到当前的序列哦,好多人的答案反了...

    当时猜了个结论就写了,早上醒来想了想证明,挺麻烦的,懒得写了,好饿啊...

    参考代码

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 
     8 const int N=10005;
     9 
    10 struct node {
    11     int s, t;
    12     void init(int a, int b) {
    13         s=a, t=b;
    14     }
    15 } ans[10];
    16 int A[10][N], n;
    17 
    18 int checkL(int dep) {
    19     if(A[dep][1]!=1) return 1;
    20     for(int i=2; i<=n; i++) if(A[dep][i]!=A[dep][i-1]+1) return i;
    21     return -1;
    22 }
    23 
    24 int checkR(int dep) {
    25     if(A[dep][n]!=n) return n;
    26     for(int i=n-1; i>=1; i--) if(A[dep][i]!=A[dep][i+1]-1) return i;
    27     return -1;
    28 }
    29 
    30 int findpos(int dep, int val) {
    31     for(int i=1; i<=n; i++) if(A[dep][i]==val) return i;
    32 }
    33 
    34 bool DFS(int dep) {
    35     if(dep==3) if(checkL(dep)!=-1) return false;
    36     else {
    37         printf("%d
    ", dep);
    38         for(int i=dep-1; i>=0; i--) printf("%d %d
    ", ans[i].s, ans[i].t);
    39         return true;
    40     }
    41 
    42     int L=checkL(dep), R=checkR(dep);
    43     if(L==-1 || R==-1) {
    44         printf("%d
    ", dep);
    45         for(int i=dep-1; i>=0; i--) printf("%d %d
    ", ans[i].s, ans[i].t);
    46         return true;
    47     }
    48     for(int i=1; i<=n; i++) A[dep+1][i]=A[dep][i];
    49     int Lpos=findpos(dep+1, L), Rpos=findpos(dep+1, R);
    50 
    51     reverse(A[dep+1]+L, A[dep+1]+Lpos+1);
    52     ans[dep].init(L, Lpos);
    53     if(DFS(dep+1)) return true;
    54     reverse(A[dep+1]+L, A[dep+1]+Lpos+1);
    55 
    56     ans[dep].init(Rpos, R);
    57     reverse(A[dep+1]+Rpos, A[dep+1]+R+1);
    58     if(DFS(dep+1)) return true;
    59     reverse(A[dep+1]+Rpos, A[dep+1]+R+1);
    60 
    61     return false;
    62 }
    63 
    64 int main() {
    65     scanf("%d", &n);
    66     for(int i=1; i<=n; i++) scanf("%d", &A[0][i]);
    67     DFS(0);
    68     return 0;
    69 }
    E

    这场比赛总算圆了我 div2 AK 一场的梦,爽,不过,题目的质量确实不怎么样...

  • 相关阅读:
    codechef Taxi Driver
    BZOJ2190 SDOI2008 仪仗队
    BZOJ 1070: [SCOI2007]修车
    BZOJ 1066 [SCOI2007]蜥蜴
    最大流模板
    表达式计算
    codechef Polo the Penguin and the Tree
    LCA 求 树中两个点的距离
    Baby Step Giant Step model
    POJ 1330 Nearest Common Ancestors (LCA,dfs+ST在线算法)
  • 原文地址:https://www.cnblogs.com/zhj5chengfeng/p/3284536.html
Copyright © 2011-2022 走看看