zoukankan      html  css  js  c++  java
  • 百斯特

    先上题目:

    10679 多少个1

    时间限制:1000MS  内存限制:65535K
    提交次数:288 通过次数:22

    题型: 编程题   语言: C++;C

     

    Description

        Acm比赛里面经常需要巧妙方法处理数据,如求给定数组的最大连续和就可用到前缀和。现在给出一个给定长度的且初始化为0的数组,
    然后对该数组的一系列区间做取反操作,最后询问数组中有多少个1。(取反操作:原来是0就变为1,是1就变为0)




    输入格式

        输入第一行是t表示case数。每个case的第一行是用空格隔开的正整数n和m(0<n<=10^18,0<=m<=100000)分别表示数组长度和总操作数,
    接下来有m行,每行包含两个整数a和b(a、b之间用空格隔开,表示将位置a和位置b之间(包含a和b)的所有位进行取反操作,0<=a,b<n)。每个case后紧接一空行。



    输出格式

       每个case第一行输出:“Case #i:”,i表示第几个Case(从1开始);第二行输出数组1的个数



     

    输入样例

    2
    2000000000 1
    0 1000000000
    
    1000 3
    0 999
    0 100
    100 100
    



     

    输出样例

    Case #1:
    1000000001
    Case #2:
    900
    

      首先是最简单的方法:读入所有的区间,然后将区间里面的所有值取反。这样做绝对超时。

      然后是深一层的方法:先对所有区间离散化,然后构造线段树,接着更新线段树的区间。思路上可行,没有用这种方法实现过,算了一下时间复杂度:

      ①排序+离散化 O(mlogm)

      ②建树 O(mlogm)

      ③更新区间 O(mlogm)

      ④最终求值O(mlogm)

      这是上界,感觉不会超,但是实现起来还是比较麻烦。

      然后说一下第三种方法:使用归一化思想,见过观察,我们可以发现更新一个区间[l,r]的操作等价于更新[l,+∞]然后再更新[r+1,+∞],所以我们可以先处理出所有的变换后的左区间,然后排一次序,从小到大排序,然后加减交替更新即可,因为更新奇数次为加,更新偶数次不变。总的时间复杂度为O(mlogm)

    上代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <utility>
     5 #include <vector>
     6 #include <algorithm>
     7 #define MAX 100002
     8 #define ll long long
     9 //#define lld I64d
    10 using namespace std;
    11 
    12 ll n,m;
    13 ll l,r;
    14 ll s[MAX<<1],tot;
    15 
    16 int main()
    17 {
    18     int t;
    19     //freopen("data.txt","r",stdin);
    20     //ios::sync_with_stdio(false);
    21     scanf("%d",&t);
    22     for(int z=1;z<=t;z++){
    23         tot=0;
    24         scanf("%lld %lld",&m,&n);
    25         for(int i=0;i<n;i++){
    26             scanf("%lld %lld",&l,&r);
    27             if(l>r) swap(l,r);
    28             s[tot++]=l;
    29             s[tot++]=r+1;
    30         }
    31         sort(s,s+tot);
    32         ll sum=0,f=1;
    33         for(int i=0;i<tot;i++){
    34             if(s[i]>m) break;
    35             if(f){
    36                 sum+=m-s[i]+1;
    37             }else{
    38                 sum-=m-s[i]+1;
    39             }
    40             f=f^1;
    41         }
    42         //cout<<"Case #"<<z<<":"<<endl<<sum<<endl;
    43         printf("Case #%d:
    %lld
    ",z,sum);
    44     }
    45     return 0;
    46 }
    10679
  • 相关阅读:
    命令提示符窗口adb shell 执行sqlite命令时进入 ...> 状态如何退出
    通过android studio 浏览模拟器中文件
    vim快捷键参考
    快速体验openstack-用devstack安装openstack
    css靠左,靠右
    全国-城市-百度地图中心点坐标
    java_dom4j解析xml
    December 31st, Week 53rd Tuesday, 2019
    December 28th, Week 52nd Saturday, 2019
    December 21st, Week 51st Saturday, 2019
  • 原文地址:https://www.cnblogs.com/sineatos/p/4223801.html
Copyright © 2011-2022 走看看