zoukankan      html  css  js  c++  java
  • Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3)

    A.Math Problem(CF 1262 A)

    题目大意:给定n条线段,求一条线段,使得这个线段能够跟所有给定的线段都相交(端点值一样也算相交),最小化它的长度,可以是0.

    很显然找出这n条线段的左端点最大值和右端点的最小值,它们的差和0的最大值即为答案。

     1 #include <bits/stdc++.h>
     2 #define MIN(a,b) (((a)<(b)?(a):(b)))
     3 #define MAX(a,b) (((a)>(b)?(a):(b)))
     4 using namespace std;
     5 
     6 template <typename T>
     7 void read(T &x) {
     8     int s = 0, c = getchar();
     9     x = 0;
    10     while (isspace(c)) c = getchar();
    11     if (c == 45) s = 1, c = getchar();
    12     while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    13     if (s) x = -x;
    14 }
    15 
    16 template <typename T>
    17 void write(T x, char c = ' ') {
    18     int b[40], l = 0;
    19     if (x < 0) putchar(45), x = -x;
    20     while (x > 0) b[l++] = x % 10, x /= 10;
    21     if (!l) putchar(48);
    22     while (l) putchar(b[--l] | 48);
    23     putchar(c);
    24 }
    25 
    26 void Input(void) {
    27     int n,l,r;
    28     l=0;
    29     r=1e9+7;
    30     read(n);
    31     for(int u,v,i=1;i<=n;++i){
    32         read(u);
    33         read(v);
    34         l=MAX(l,u);
    35         r=MIN(v,r);
    36     }
    37     printf("%d
    ",MAX(l-r,0));
    38 }
    39 
    40 void Solve(void) {}
    41 
    42 void Output(void) {}
    43 
    44 main(void) {
    45     int kase;
    46     freopen("input.txt", "r", stdin);
    47     freopen("output.txt", "w", stdout);
    48     read(kase);
    49     for (int i = 1; i <= kase; i++) {
    50         //printf("Case #%d: ", i);
    51         Input();
    52         Solve();
    53         Output();
    54     }
    55 }
    神奇的代码

    B.Box(CF 1262 B)

    题目大意:给出一个排列每一个位置的前缀最大值,还原该排列,答案可能有多种,还原任意一种即可。

    输入max[i],如果max[i-1]<max[i],则第i位一定是max[i].

    如果max[i-1]=max[i],则我们可以选择小于max[i]的未出现的数作为第i位,贪心构造即可。当没有数可以选择的时候则说明没有排列满足该条件。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 template <typename T>
     5 void read(T &x) {
     6     int s = 0, c = getchar();
     7     x = 0;
     8     while (isspace(c)) c = getchar();
     9     if (c == 45) s = 1, c = getchar();
    10     while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    11     if (s) x = -x;
    12 }
    13 
    14 template <typename T>
    15 void write(T x, char c = ' ') {
    16     int b[40], l = 0;
    17     if (x < 0) putchar(45), x = -x;
    18     while (x > 0) b[l++] = x % 10, x /= 10;
    19     if (!l) putchar(48);
    20     while (l) putchar(b[--l] | 48);
    21     putchar(c);
    22 }
    23 int n,l,ans[100050];
    24 bool used[100050];
    25 void Input(void) {
    26     read(n);
    27     for(int i=1;i<=n;++i) used[i]=true;
    28     l=1;
    29     ans[0]=0;
    30     bool qwq=false;
    31     for(int u,v=0,i=1;i<=n;++i){
    32         read(u);
    33         if (qwq) continue;
    34         if (u>v){
    35             used[u]=false;
    36             ans[i]=u;
    37             v=u;
    38             continue;
    39         }
    40         while(l<u&&used[l]==false) ++l;
    41         if (l==u){
    42             qwq=true;
    43             continue;
    44         }
    45         ans[i]=l;
    46         used[l]=false;
    47     }
    48     if (qwq) printf("-1
    ");
    49     else{
    50         for(int i=1;i<=n;++i) printf("%d%c",ans[i],i==n?'
    ':' ');
    51     }
    52 }
    53 
    54 void Solve(void) {}
    55 
    56 void Output(void) {}
    57 
    58 main(void) {
    59     int kase;
    60     freopen("input.txt", "r", stdin);
    61     freopen("output.txt", "w", stdout);
    62     read(kase);
    63     for (int i = 1; i <= kase; i++) {
    64         //printf("Case #%d: ", i);
    65         Input();
    66         Solve();
    67         Output();
    68     }
    69 }
    神奇的代码

    C.Messy (CF 1262 C)

    题目大意:给定一个括号串,我们可以翻转某一区间的括号,即对[l...r]翻转,则变成[r...l],然后我们需要进行不超过n次操作,使得该括号串合法,且对于所有该串的前缀子串,有k个合法子串,输出操作次数以及前后分别进行的操作的区间的左端点和右端点,注意只要小于n即可,不需要最小。题目保证有解。

    所有子串有k个合法前缀子串,即整个子串分成了k份,我们对某一份中的()交换,则将该份子串拆成两份,我们把两份子串的接触点)(交换,则这两个子串合并成一个,所以我们关键是如何让该子串合法,然后就不会了qwq

    坑待填填坑啦!!!

    注意到n不大,我们可以构造一个符合条件的括号序列ans,然后将初始序列que按照构造的序列进行翻转,即考虑第i个位置,若ans[i]==que[i]则continue,若不相等则找一个最小的大于i的j,有ans[i]==que[j],然后对que的区间[i,j]进行翻转,复杂度O(n2)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 template <typename T>
     5 void read(T &x) {
     6     int s = 0, c = getchar();
     7     x = 0;
     8     while (isspace(c)) c = getchar();
     9     if (c == 45) s = 1, c = getchar();
    10     while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    11     if (s) x = -x;
    12 }
    13 
    14 template <typename T>
    15 void write(T x, char c = ' ') {
    16     int b[40], l = 0;
    17     if (x < 0) putchar(45), x = -x;
    18     while (x > 0) b[l++] = x % 10, x /= 10;
    19     if (!l) putchar(48);
    20     while (l) putchar(b[--l] | 48);
    21     putchar(c);
    22 }
    23 int n,k;
    24 
    25 int op[2006][2];
    26 
    27 char ans[2005],que[2005];
    28 
    29 void change(int st,int en){
    30     char qwq[2005];
    31     int l=0;
    32     for(int i=st;i<=en;++i) qwq[l++]=que[i];
    33     for(int i=st;i<=en;++i) que[i]=qwq[--l];
    34 }
    35 void Input(void) {
    36     read(n);
    37     read(k);
    38     int m=0;
    39     scanf("%s",que);
    40     for(int i=1;i<=(n-2*(k-1))/2;++i)
    41         ans[m++]='(';
    42     for(int i=1;i<=(n-2*(k-1))/2;++i)
    43         ans[m++]=')';
    44     for(int i=1;i<k;++i){
    45         ans[m++]='(';
    46         ans[m++]=')';
    47     }
    48     m=0;
    49     for(int i=0;i<n;++i){
    50         if (ans[i]!=que[i]){
    51             int j=i+1;
    52             while(ans[i]!=que[j]) ++j;
    53             change(i,j);
    54             op[++m][0]=i+1;
    55             op[m][1]=j+1;
    56         }
    57     }
    58     write(m,'
    ');
    59     for(int i=1;i<=m;++i) printf("%d %d
    ",op[i][0],op[i][1]);
    60 }
    61 
    62 void Solve(void) {}
    63 
    64 void Output(void) {}
    65 
    66 main(void) {
    67     int kase;
    68     freopen("input.txt", "r", stdin);
    69     freopen("output.txt", "w", stdout);
    70     read(kase);
    71     for (int i = 1; i <= kase; i++) {
    72         //printf("Case #%d: ", i);
    73         Input();
    74         Solve();
    75         Output();
    76     }
    77 }
    神奇的代码

     

    D.Optimal Subsequences(CF 1262 D1、D2)

    题目大意:给定一个长度为n的数组,求一个长度为k的最佳序列,该序列满足两个条件:其和是所有长度相同的序列的和的最大值;该序列是所有长度相同且和最大的序列中,其数字构成的序列的字典序最小,输出该序列的第pos位的数字,多次询问。

    很容易想到我们可以先对k进行从小到大排序,依次构造出长度为k的最佳序列,其构造方法很容易想到,即设最佳序列的数组为a,数大的先添加进a数组,数相等的位置在前的先添加。

    但关键在于如何找到该序列中第pos位的数字。

    我们新设一个数组cnt,cnt[i]表示第i个数字被选中了,记为1,否则为0,然后我们用树状数组来维护cnt数组的前缀和,当某位的前缀和为pos,且该位被选中了,则该位的数字即为所求答案。由于前缀和单调递增,我们可以采用二分,即可在O(log2n)时间内找出。

    总时间复杂度是O(mlog2n+mlogm)

     

    当时做的时候逆过来,k从大到小排序,然后在原数组删数,树状数组维护前i个数中被删去的个数,则对于在原数组第i位且未被删去的数,它在最佳序列的位置即为i-sum[i],同样二分找即可。

      1 #include <bits/stdc++.h>
      2 #define lowbit(x)  ((x&(-x)))
      3 using namespace std;
      4 
      5 template <typename T>
      6 void read(T &x) {
      7     int s = 0, c = getchar();
      8     x = 0;
      9     while (isspace(c)) c = getchar();
     10     if (c == 45) s = 1, c = getchar();
     11     while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
     12     if (s) x = -x;
     13 }
     14 
     15 template <typename T>
     16 void write(T x, char c = ' ') {
     17     int b[40], l = 0;
     18     if (x < 0) putchar(45), x = -x;
     19     while (x > 0) b[l++] = x % 10, x /= 10;
     20     if (!l) putchar(48);
     21     while (l) putchar(b[--l] | 48);
     22     putchar(c);
     23 }
     24 
     25 struct data{
     26     int val,id;
     27     bool operator < (const data &b) const{
     28         if (val>b.val) return true;
     29         if (val<b.val) return false;
     30         if (id<b.id) return true;
     31         return false;
     32     }
     33 };
     34 
     35 const int N=2e5+5;
     36 
     37 struct date{
     38     int k,pos,id;
     39 }que[N];
     40 
     41 priority_queue<data> qwq;
     42 
     43 int n,m;
     44 
     45 int tree[N],a[N],ans[N];
     46 
     47 bool dell[N];
     48 
     49 bool cmp(const struct date &a,const struct date &b){
     50     if (a.k>b.k) return true;
     51     if (a.k<b.k) return false;
     52     if (a.pos<b.pos) return false;
     53     return true;
     54 }
     55 
     56 void Input(void) {
     57     read(n);
     58     for(int i=1;i<=n;++i) {
     59         read(a[i]);
     60         qwq.push(data{a[i],i});
     61     }
     62     read(m);
     63     for(int i=1;i<=m;++i){
     64         que[i].id=i;
     65         read(que[i].k);
     66         read(que[i].pos);
     67     }
     68 }
     69 
     70 void tree_insert(int x){
     71     for(int i=x;i<=n;i+=lowbit(i))
     72         tree[i]++;
     73 }
     74 
     75 int tree_sum(int x){
     76     int a=0;
     77     for(int i=x;i>=1;i-=lowbit(i))
     78         a+=tree[i];
     79     return a;
     80 }
     81 
     82 int find_pos(int x){
     83     int l=1,r=n;
     84     while(l<=r){
     85         int mid=(l+r)>>1;
     86         int tmp=tree_sum(mid);
     87         if (mid-tmp>x) r=mid;
     88         else if (mid-tmp==x) if (dell[mid]==false) return a[mid];
     89         else r=mid;
     90         else l=mid+1;
     91     }
     92     return 0;
     93 } 
     94 
     95 void Solve(void) {
     96     sort(que+1,que+1+m,cmp);
     97     int qvq=n;
     98     for(int i=1;i<=m;++i){
     99         int dis=qvq-que[i].k;
    100         qvq=que[i].k;
    101         while(dis--){
    102             data qaq=qwq.top();
    103             dell[qaq.id]=true;
    104             tree_insert(qaq.id);
    105             qwq.pop();
    106         }
    107         ans[que[i].id]=find_pos(que[i].pos);
    108     }
    109 }
    110 
    111 void Output(void) {
    112     for(int i=1;i<=m;++i) printf("%d
    ",ans[i]);
    113 }
    114 
    115 main(void) {
    116     freopen("input.txt", "r", stdin);
    117     freopen("output.txt", "w", stdout);
    118     Input();
    119     Solve();
    120     Output();
    121 }
    神奇的代码

    (以为会T的结果才跑了200+ms?)

    E. Arson In Berland Forest (CF 1262 E)

    题目大意:某森林发生火灾,一棵树如果着火,下一个时刻火焰回向四周八个方向蔓延,给定当前局面的着火情况,最大化着火时间,并给定初始时刻(T=0)时树的起火情况。如果有多种情况输出任意一种即可。

    最暴力的做法自然是从着火边缘不断灭火,时刻加一,直到某一时刻,如果灭了火之后不能还原成原来的着火情况,则当前时刻为最大的着火时间,其复杂度为O(nmT),T能取到min(m,n)的数量级,显然会T。

    但是我们从暴力做法中发现,局面是否可行具有单调性,于是我们可以二分时间来判断是否可行,复杂度降为O(nm*logT),T=min(n,m)

    至于验证方法,(听说BFS卡常?),我们可以先根据X预处理二维前缀和,在二分某个时间t时,找到每个含有(2*t+1)*(2*t+1)个X的区域,把它缩成中心点(在判断的时候它们还是保留为X的),最后再还原判断是否为原来的局面(因为可能存在不够(2*t+1)*(2*t+1)个X的区域,使得它无法缩为点,而我们只是把所有含有(2*t+1)*(2*t+1)个X的区域缩为点而已)。判断的话我们令着火区域的值增加1,运用二维差分来维护某区域的值,即可在最后判断每个点的着火情况与原图是否一致。

     1 #include <bits/stdc++.h>
     2 #define MIN(a,b) ((((a)<(b)?(a):(b))))
     3 #define MAX(a,b) ((((a)>(b)?(a):(b))))
     4 #define ABS(a) ((((a)>0?(a):-(a))))
     5 #define POS(i,j) (((i)*(m+2)+(j)))
     6 using namespace std;
     7 
     8 template <typename T>
     9 void read(T &x) {
    10     int s = 0, c = getchar();
    11     x = 0;
    12     while (isspace(c)) c = getchar();
    13     if (c == 45) s = 1, c = getchar();
    14     while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    15     if (s) x = -x;
    16 }
    17 
    18 template <typename T>
    19 void write(T x, char c = ' ') {
    20     int b[40], l = 0;
    21     if (x < 0) putchar(45), x = -x;
    22     while (x > 0) b[l++] = x % 10, x /= 10;
    23     if (!l) putchar(48);
    24     while (l) putchar(b[--l] | 48);
    25     putchar(c);
    26 }
    27 
    28 const int N=3e6+8;
    29 
    30 int n,m,cnt;
    31 
    32 int sum[N],now[N],ans[N];
    33 
    34 char ma[N];
    35 
    36 
    37 void Input(void) {
    38     read(n);
    39     read(m);
    40     memset(sum,0,sizeof(sum));
    41     for(int i=1;i<=n;++i) scanf("%s",ma+POS(i,1));
    42     for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) sum[POS(i,j)]=(ma[POS(i,j)]=='X');
    43     for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) sum[POS(i,j)]+=sum[POS(i-1,j)];
    44     for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) sum[POS(i,j)]+=sum[POS(i,j-1)];
    45     cnt=0;
    46 }
    47 
    48 bool check(int x){
    49     ++cnt;
    50     memset(now,0,sizeof(now));
    51     for(int i=1+x;i<=n-x;++i) for(int j=1+x;j<=m-x;++j){
    52         if ((sum[POS(i+x,j+x)]-sum[POS(i-x-1,j+x)]-sum[POS(i+x,j-x-1)]+sum[POS(i-x-1,j-x-1)])!=((2*x+1)*(2*x+1))) continue;
    53         ans[POS(i,j)]=cnt;
    54         now[POS(i-x,j-x)]++;
    55         now[POS(i+x+1,j+x+1)]++;
    56         now[POS(i-x,j+x+1)]--;
    57         now[POS(i+x+1,j-x)]--;
    58     }
    59     for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) now[POS(i,j)]+=now[POS(i-1,j)];
    60     for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) now[POS(i,j)]+=now[POS(i,j-1)];
    61     for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if ((ma[POS(i,j)]=='X')^(now[POS(i,j)]!=0)) return false;
    62     return true;
    63 }
    64 void Solve(void) {
    65     int T=0,l=0,r=((MIN(n,m)>>1)+1);
    66     int tt=0;
    67     while(l<r){
    68         int mid=(l+r)>>1;
    69         if (check(mid)) T=mid,l=mid+1,tt=cnt;
    70         else r=mid;
    71     }
    72     write(T,'
    ');
    73     for(int i=1;i<=n;++i) {
    74         for(int j=1;j<=m;++j) 
    75             printf("%c",ans[POS(i,j)]>=tt?'X':'.');
    76         puts("");
    77     }
    78 }
    79 
    80 void Output(void) {}
    81 
    82 main(void) {
    83     freopen("input.txt", "r", stdin);
    84     freopen("output.txt", "w", stdout);
    85     Input();
    86     Solve();
    87     Output();
    88 }
    神奇的代码

    原图n,m都有可能到达1e6但相乘不会大于1e6,然后用了二维到一维的映射函数POS,由于正常标号可能会变成负数导致RE,就稍微改了下映射关系。

  • 相关阅读:
    ORACLE 变量定义
    AcWing1082 数字游戏(数位dp)
    AcWing1081 度的数量(数位dp)
    UCF Local Programming Contest 2017 I题 Rotating Cards(贪心+树状数组)
    AcWing1048 鸡蛋的硬度(浅谈两种解法的思考方向)
    CF713C Sonya and Problem Wihtout a Legend (经典dp)
    CF269B Greenhouse Effect (dp LIS)
    CF463D Gargari and Permutations (LCS)
    AcWing987 最长公共子序列
    CF721C Journey (dp+拓扑)
  • 原文地址:https://www.cnblogs.com/Lanly/p/11924231.html
Copyright © 2011-2022 走看看