• 华东交通大学2019年ACM“双基”程序设计竞赛 H-谁在说谎 BZOJ2298 洛谷P2519


    题目链接:https://ac.nowcoder.com/acm/contest/1168/H

    注解代码里有,大致思路就是把输入数据转换成线段,有重复的线段可以累加,但是最大不能超过该线段的长度,然后找出最大的不重合区间,其他没计入的都是说谎的人

    #include<bits/stdc++.h>
    #include<vector>
    #include<map>
    #include<queue>
    #define LL long long
    #define INF 0x3f3f3f3f
    #define MOD 1000000007
    using namespace std;
    int dp[100005];
    struct node
    {
        int l;
        int r;
    }a[100005];
    bool cmp(node x, node y)
    {
        if(x.r == y.r)
            return x.l < y.l;
        else
            return x.r < y.r;
    }
    int main()
    {
        int n, x, y, pos = 1;
        scanf("%d", &n);
        for(int i = 1;i <= n;i++)
        {
            scanf("%d%d", &x, &y);
            if(x+y < n)                         //防止出现负数
            {
                a[pos].l = x+1;                 //求出这个人所在区间
                a[pos].r = n-y;
                pos++;
            }
        }
        sort(a+1, a+pos+1, cmp);                //排序,以右区间为判断条件,小的在前面,右区间相同的左区间小的在前面
        int j = 1, flag = 0;
        for (int i = 1;i <= n;i++)
        {
            dp[i] = dp[i-1];                    //dp记录当前说真话的人数
            while(a[j].r < i)                   //右区间比i小的都是说谎的人
            {
                j++;
                if(j > 100000)                  //当j大于n时跳出循环,否则会段错误
                {
                    flag = 1;
                    break;
                }
            }
            int temp = 0;
            while(a[j].r == i)                  //如果在一个说谎的人之后是数个右区间相同的人,这里会直接从最后一个开始遍历
            {                                   //因为当a[j].r大于i时整个循环只会进行dp数组的传递和i++
                if(a[j].l == a[j-1].l)          //左区间也相同时累加
                    temp++;
                else
                    temp = 1;
                dp[i] = max(dp[i], dp[a[j].l-1] + min(temp, i - a[j].l + 1));//
                j++;             //dp[a[j].l-1]是上一段不重合的区间
            }
            if(flag)                            //前面a[j].r都小于i时j会一直加到100000,此时dp[n]的值是0
            {                                   //所以需要从n开始往前回溯到有值的dp[i]再把值赋给dp[n]
                for(int i = n;i >= 1;i--)
                {
                    if(dp[i])
                    {
                        dp[n] = dp[i];
                        break;
                    }
                }
                break;
            }
        }
        printf("%d
    ", n-dp[n]);
        return 0;
    }

    这道题洛谷,bzoj上面都有,但是华交好像加了几组数据,卡了我好久………没后台数据就是难找bug,还是codeforces好啊

  • 相关阅读:
    MPLS 知识要点1
    ISIS的SSN和SRM标志
    对比ISIS和OSPF
    ISIS帧中继实验
    ISIS 认证实验
    ISIS数据库同步
    ISIS Lab 路由泄露
    ISIS Lab 重分布直连
    32、端口有效范围是多少到多少?
    33、为何需要把 TCP/IP 协议栈分成 5 层(或7层)?开放式回答。
  • 原文地址:https://www.cnblogs.com/Mamba0Z/p/11885176.html
Copyright © 2020-2023  润新知