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 ;
                        }
                    }
                }
            }
        }
    }
    
  • 相关阅读:
    安装IIS
    安装Asp.Net(4.0.30319)
    转载一个博文
    文件操作引出流(二)FileStream和
    《学习之道》第十一章目前此章最后一点-重复
    《学习之道》第十一章意群
    Views
    Django的基本使用
    MVC框架
    Zookeeper
  • 原文地址:https://www.cnblogs.com/rayrayrainrain/p/6275757.html
Copyright © 2011-2022 走看看