zoukankan      html  css  js  c++  java
  • Codeforces Round #390 (Div. 2) A B C D

    这是一场比较难的div2 ... 比赛的时候只出了AB

    A很有意思 给出n个数 要求随意的把相邻的数合并成任意多数 最后没有为0的数 输出合并区间个数与区间 

    可以想到0可以合到任何数上并不改变该数的性质 所以如果不全是0 最后一定是有答案的 把所有的0都合并到最近的非0数上去 非0数不变

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<map>
    #include<string>
    #include<vector>
    #include<queue>
    #include<iostream>
    using namespace std;
    #define L long long
    int n ;
    int a[105];
    int l[105];
    int r[105];
    int main(){
        scanf("%d",&n);
        for(int i = 1 ;i<=n;i++)scanf("%d",&a[i]);
        bool ok = true;
        int res = 0;
        int cnt = 0;
        for(int i = 1; i<=n;i++){
            if(a[i]!= 0){
                cnt ++ ;
                l[cnt] = i;
                r[cnt] = i;
            }
        }
        if(cnt == 0){
            printf("NO
    ");
            return 0 ;
        }
        r[0] = 0 ;
        l[cnt+1] = n + 1;
        for(int i = 1; i<= cnt ;i ++){
            l[i] = r[i-1] + 1;
            r[i] = l[i+1] - 1;
        }
        printf("YES
    ");
        printf("%d
    ",cnt);
        for(int i = 1 ; i<=cnt ; i ++){
            printf("%d %d
    ",l[i],r[i]);
        }
    }
    

    B很无聊..下三子棋 现在该我们下x了 能否一步胜利或者不走就胜利了呢?

    写一个很手动的check函数 先判断能否直接胜利 再枚举每一个可以放的位置 放下再check

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<map>
    #include<string>
    #include<vector>
    #include<queue>
    #include<iostream>
    using namespace std;
    #define L long long
    char s[50][50];
    bool check(char a){
        for(int i = 1 ; i<=4 ; i ++){
            for(int j = 1 ; j<= 2 ; j ++ ){
                if(s[i][j] == s[i][j+1] &&s[i][j+1] == s[i][j+2] && s[i][j+1] == a){
                    return true;
                }
            }
        }
        for(int j = 1 ; j<=4 ; j ++){
            for(int i = 1 ; i<= 2 ; i ++ ){
                if(s[i][j] == s[i+1][j] &&s[i+1][j] == s[i+2][j] && s[i][j] == a){
                    return true;
                }
            }
        }
        for(int i = 1; i<=2 ;i ++){
            if(s[i][i] == s[i+1][i+1] &&s[i+1][i+1] == s[i+2][i+2] && s[i][i] == a)return true ;
        }
        if(s[2][1] == s[3][2] && s[3][2] == s[4][3] &&s[4][3] == a)return true;
        if(s[1][2] == s[2][3] && s[2][3] == s[3][4] &&s[3][4] == a)return true;
    
        if(s[2][4] == s[3][3] && s[3][3] == s[4][2] &&s[4][2] == a)return true;
        if(s[1][3] == s[2][2] && s[2][2] == s[3][1] &&s[3][1] == a)return true;
    
        if(s[1][4] == s[2][3] && s[2][3] == s[3][2] && s[3][2] == a)return true;
        if(s[2][3] == s[3][2] && s[3][2] == s[4][1] && s[4][1] == a)return true;
         return false ;
    }
    int main(){
        for(int i = 1;i<=4 ; i++)scanf("%s",s[i] + 1);
        if(check('x')){
            printf("YES
    ");
            return 0;
        }
        if(check('o')){
            printf("NO
    ");
            return 0 ;
        }
        for(int i = 1 ; i <= 4;i++){
            for(int j = 1 ; j<=4 ;j ++){
                if(s[i][j] == '.'){
                    s[i][j] = 'x';
                    if(check('x')){
                        printf("YES
    ");
                        return 0 ;
                    }
                    s[i][j] = '.';
                }
            }
        }
        printf("NO
    ");
    }
    

    C一个比较耗费时间的字符串模拟 给出一些人的名字和他们说的话 有些话的发言人用?代替 要求 相邻的两句话不会是同一个人说的 一个人说的话不会提到自己的名字

    先做一个字符串模拟 用map把人名编号 再用r[]记录每句话的发言人 用cx[][]来记录每句话中出现的人名 用ans[]来处理最后的答案 

    最后我们 会得到一个cx数组 记录每句没有主人的话能选择的人

    会发现贪心好像是不可做的 当前这句话 如果我们做出一些选择 可能会影响到下一个人的选择

    搜索的话 如果100句话都是?也会超时

    可以利用cx[][]数组和r[]数组 做一个dp题

    如果想不到怎么dp 可以去代码中寻找注释~

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<map>
    #include<string>
    #include<vector>
    #include<queue>
    #include<iostream>
    using namespace std;
    #define L long long
    string name[1050];
    map<string , int >p;
    int n , m ;
    char s[1050];
    string ans[1050];
    int r[1050];
    bool cx[105][105];
    
    int cnt ;
    int us[105];
    
    int main(){
        int t;
        scanf("%d",&t);
        while(t -- ){
            memset(r , -1 ,sizeof(r));
            scanf("%d",&n);
            p.clear();
            string tm = "";
            for(int i = 1; i<=n ;i ++){
                scanf("%s",s);
                int len = strlen(s);
                tm = "" ;
                for(int j = 0 ; j<len ;j ++)tm += s[j];
                p[tm] = i ;
                name[i] = tm ;
            }
            scanf("%d",&m);
            getchar();
            bool ok = true;
            memset(cx , false,sizeof(cx));
            for(int i = 1; i<=m;i ++){
                gets(s);
                int len = strlen(s);
                ans[i] = "";
                if(s[0] == '?'){
                    r[i] = -1;
                    for(int j = 2 ; j<len ; j ++){
                        tm = "";
                        while(j < len && s[j] != '.' && s[j] != ',' && s[j] != '!' && s[j] != '?' && s[j] != ' '){
                            tm += s[j] ;
                            j ++ ;
                        }
                        if(tm != ""){
                            int z = p[tm];
                            if(z != 0){
                                cx[i][z] = true ;
                            }
                        }
                    }
                    for(int j = 1 ; j < len ; j ++)ans[i] += s[j] ;
                }
                else {
                    tm = "" ;
                    int j ;
                    for(j = 0; s[j] !=':' ; j ++ ){
                        tm += s[j];
                    }
                    r[i] = p[tm];
                    j ++ ;
                    for(int k = 0 ; k < len ;k ++)ans[i] += s[k] ;
                    for(; j<len ; j ++){
                        tm = "";
                        while(j < len && s[j] != '.' && s[j] != ',' && s[j] != '!' && s[j] != '?' && s[j] != ' '){
                            tm += s[j] ;
                            j ++ ;
                        }
                        if(tm != ""){
                            int z = p[tm];
                            if(z != 0){
                                cx[i][z] = true ;
                            }
                        }
                    }
                }
             }
             if(ok == false) {
                printf("Impossible
    ");
                continue ;
             }
             r[0] = r[m+1] = -1 ;
             /**
                r[i] 第几句话发言人的编号 -1代表?
                name[] 1-n号人的名字
                cx[u][v] 第u句话中提到了v
    
             */
             bool dp[105][105] ;
             int pre[105][105] ;
             /**
                dp[i-1][!j] == true  -> dp[i][j] = true
                pre[i][j] = pre[i-1][!j]
             */
             memset(dp , false , sizeof(dp)) ;
             for(int i = 1 ; i <= n ; i ++ )dp[0][i] = true ;
             for(int i = 1 ; i <= m ; i ++ ){
                if(r[i] != -1) {
                    if(i == 1) {
                        dp[i][r[i]] = true ;
                        continue ;
                    }
                    for(int j = 1; j <= n ; j ++ ){
                        if(j != r[i] && dp[i-1][j] == true) {
                            dp[i][r[i]] = true ;
                            pre[i][r[i]] = j ;
                        }
                    }
                    continue ;
                }
                for(int j = 1; j <=n ; j ++ ){
                    if(cx[i][j] == true) continue ;
                    if(j == r[i+1]) continue ;
                    if(j == r[i-1]) continue ;
                    for(int k = 1; k <= n ; k ++ ){
                        if(j == k && i != 1)continue ;
                        if(dp[i-1][k] == true){
                            dp[i][j] = true ;
                            pre[i][j] = k ;
                        }
                    }
                }
             }
             /// 利用pre数组反转录入答案
             cnt = m ;
             bool fin = false ;
             for(int i = 1; i <= n ;i ++ ){
                if(dp[m][i] == true){
                    us[cnt] = i ;
                    int w = i;
                    while(cnt >= 2) {
                        int k = pre[cnt][w] ;
                        cnt -- ;
                        us[cnt] = k ;
                        w = k ;
                    }
                    fin = true ;
                    break ;
                }
             }
             if(fin == false){
                printf("Impossible
    ");
                continue ;
             }
             ///ans
             for(int i = 1; i <= m ; i ++ ){
                if(r[i] != -1){
                    cout << ans[i] << endl ;
                }
                else {
                    cout << name[us[i]] << ans[i] << endl ;
                }
             }
        }
    }
    

    D给出n个区间 要求必须选择k个区间 使这k个区间的交集最大

    k个区间的交集形成的区间 它的l是这几个区间中的最大的l 而r是这几个区间中的最小的r

    应当选择k个区间 使它们有最小的l和最大的r 所以动态的去想 我们可以将l从小往大选 并选择最大化的r 维护一个ans

    先进行排序 使l尽可能的小 在其基础上r尽可能的小 这样 我们从1-n枚举区间 就可以直接得到最大的l了

    因为我们选择的l 是逐渐增大的 所以为了保存足够大的r 需要一个优先队列来做 维护一个 < 的优先队列 存放每个区间的r

    1-n枚举区间的过程 每次我们选择一个区间 向优先队列中压入它的r 如果当前队列的size < k 说明未达到题目要求 暂且不管

    如果size > k  我们就q.pop 弹出当前最小的r 由于我们是动态维护了ans 所以 如果弹出最小的r 使我们失去了一个l 

    1 如果这个l 是当前区间最大的l 那么当前结果已经保留进了ans 

    2 如果这个l 不是当前区间最大的l 那么这个区间的移除会使ans增大

    如果size == k 这个状态可能是size < k 或者 size > k 来的 如果是前者 我们就需要开始更新ans(事实上这一幕只会在第k个数字出现) 

    如果是后者 我们就需要分析 这个新区间 会不会已经被弹出去了?

    1 弹出去了 那么现在其实没变化 不需要做什么改变

    2 没弹出去 那么现在就需要更新一下答案 我们可以肯定 当前的交集区间的l 一定是新区间的l(sort的结果) 而r 就是优先队列的top 所以 res = q.top - 新区间.l + 1

    判断是否弹出 需要判断新区间的r与top的关系

    有一个问题是 新区间的r 可能已经被弹出去了 当前区间并没有加进去 但是因为优先队列有r=新区间.r 所以被误判

    其实是不会造成影响的 因为对于这种情况 一定会有过去的res >= 现在的res

    所以这样模拟完最后就可以得出ans了 

    题目要求输出一下区间的选择 

    如果ans是0 随便输出k个数就可以了 

    如果不是的话 由于我们不确定当前解是不是最优解 所以 过程中我们无法更新区间数的ans

    但是我们可以在优先队列中 伴随r加上一个id 然后再跑一遍枚举 当res == ans的时候 队列里的id就是答案啦

    聪明的你一定看到这里就完全理解了吧

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<map>
    #include<string>
    #include<vector>
    #include<queue>
    #include<iostream>
    using namespace std;
    #define L long long
    int n , m ;
    struct node {
        int l , r ;
        int id ;
        bool operator < (const node &a )const{
            return a.r < r ;
        }
    }a[300050];
    bool cmp(node a, node b ){
        if(a.l == b.l )return a.r < b.r ;
        else {
            return a.l < b.l ;
        }
    }
    int c[300050] ;
    int main(){
        scanf("%d%d",&n, &m );
        for(int i = 1; i <= n ;i ++ ){
            scanf("%d%d",&a[i].l , & a[i].r ) ;
            a[i].id = i ;
        }
        sort(a+1,a+1+n,cmp) ;
        int ans = 0 ;
        priority_queue<node>q;
        int l = 0;
        for(int i = 1; i <= n ; i ++ ){
            node b = a[i] ;
            q.push(b) ;
            if(q.size() < m){
                l = a[i].l ;
            }
            if(q.size() > m){
                q.pop() ;
            }
            if(q.size() == m){
                if(b.r >= q.top().r){
                    int res = q.top().r - b.l + 1 ;
                    if(res > ans)ans = res ;
                    l = b.l ;
                }
            }
        }
        printf("%d
    ",ans) ;
        if(ans == 0){
            for(int i = 1; i <= m ; i ++ ){
                printf("%d",i);
                if(i == m)printf("
    ");
                else printf(" ");
            }
        }
        else {
            while(!q.empty())q.pop();
    
            for(int i = 1; i <= n ; i ++ ){
                node b = a[i] ;
                q.push(b) ;
                if(q.size() < m){
                    l = a[i].l ;
                }
                if(q.size() > m){
                    q.pop() ;
                }
                if(q.size() == m){
                    if(b.r >= q.top().r){
                        int res = q.top().r - b.l + 1 ;
                        if(res == ans){
                            int z = q.size();
                            while(!q.empty()){
                                c[z] = q.top().id ;
                                q.pop() ;
                                z-- ;
                            }
                            sort(c+1,c+1+m);
                            for(int j = 1; j <=m ;j ++ ){
                                printf("%d",c[j]);
                                if(j == m)printf("
    ");
                                else printf(" ");
                            }
                            break ;
                        }
                    }
                }
            }
        }
    }
    
  • 相关阅读:
    JavaScript实现类的private、protected、public、static以及继承
    OSS网页上传和断点续传(STSToken篇)
    OSS网页上传和断点续传(OSS配置篇)
    Linq sum()时遇到NULL
    SQLSERVER事务日志已满 the transaction log for database 'xx' is full
    笔记本高分辨软件兼容问题,字体太小或模糊
    H5上传图片之canvas
    An error occurred while updating the entries. See the inner exception for details.
    无限级结构SQL查询所有的下级和所有的上级
    SQLserver 进程被死锁问题解决
  • 原文地址:https://www.cnblogs.com/rayrayrainrain/p/6275757.html
Copyright © 2011-2022 走看看