zoukankan      html  css  js  c++  java
  • DAY 4 基础算法

    基础算法

    本来今天是要讲枚举暴力还有什么的,没想到老师就说句那种题目就猪国杀,还说只是难打,不是难。。。。

    STL(一)set

    感觉今天讲了好多,set,单调栈,单调队列,单调栈和单调队列保证了序列的单调性,一般的,凡是找左右第一个比他大或小的大概率是这个东西,原来作业1的奶牛歌声就是这个东西,但不是道为什么我爆力优化过了。。。。

    然后就是这题

     这题要用set,不用还过不了。。。。

    set常用函数

    • begin()        ,返回set容器的第一个元素
    • end()      ,返回set容器的最后一个元素
    • clear()          ,删除set容器中的所有的元素
    • empty()    ,判断set容器是否为空
    • max_size()   ,返回set容器可能包含的元素最大个数
    • size()      ,返回当前set容器中的元素个数
    • rbegin     ,返回的值和end()相同
    • rend()     ,返回的值和rbegin()相同

    可以这样练下手

     1 #include<iostream>
     2 #include<set>
     3 using namespace std;
     4 int main()
     5 {
     6     set<int >s;
     7     s.insert(1);
     8     s.insert(2);
     9     s.insert(3);
    10     s.insert(4);
    11     cout<<"长度是"<<s.size()<<endl;
    12     cout<<"可能包含元素的最大个数为"<<s.max_size() <<endl;
    13     cout<<"第一个元素是"<< *s.begin()<<endl;
    14     cout<<"最后一个元素是"<<*s.end()<<endl;
    15     s.clear();
    16     if(s.empty())
    17     {
    18         cout<<"空啦!!!!"<<endl; 
    19     }
    20         cout<<"长度是"<<s.size()<<endl;
    21     cout<<"可能包含元素的最大个数为"<<s.max_size() <<endl;
    22 }        

     输出是这样的:

     

    注意如果这样打

     1 #include<iostream>
     2 #include<set>
     3 using namespace std;
     4 int main()
     5 {
     6     set<int >s;
     7     s.insert(1);
     8     s.insert(2);
     9     s.insert(3);
    10     s.insert(1);
    11     cout<<"第一个元素是"<< *s.begin()<<endl;
    12     cout<<"最后一个元素是"<<*s.end()<<endl;
    13     return 0;
    14 }

     我们可以发现最后一个元素显示还是3.。。

     

    • count() 用来查找set中某个某个键值出现的次数

    这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。

     1 #include<iostream>
     2 #include<set>
     3 using namespace std;
     4 int main()
     5 {
     6     set<int >s;
     7     s.insert(1);
     8     s.insert(2);
     9     s.insert(3);
    10     s.insert(1);
    11     cout<<"set 中 1 出现的次数是 :"<<s.count(1)<<endl;
    12     cout<<"set 中 4 出现的次数是 :"<<s.count(4)<<endl;
    13     return 0;
    14 }

     输出应该是这样的

    • equal_range() ,返回一对定位器,分别表示第一个大于或等于给定关键值的元素和 第一个大于给定关键值的元素,这个返回值是一个pair类型,如果这一对定位器中哪个返回失败,就会等于end()的值。

     

     1 #include <iostream>
     2 #include <set>
     3 
     4 using namespace std;
     5 
     6 int main()
     7 {
     8     set<int> s;
     9     set<int>::iterator iter;
    10     for(int i = 1 ; i <= 5; ++i)
    11     {
    12         s.insert(i);
    13     }
    14     for(iter = s.begin() ; iter != s.end() ; ++iter)
    15     {
    16         cout<<*iter<<" ";
    17     }
    18     cout<<endl;
    19     pair<set<int>::const_iterator,set<int>::const_iterator> pr;
    20     pr = s.equal_range(3);
    21     cout<<"第一个大于等于 3 的数是 :"<<*pr.first<<endl;
    22     cout<<"第一个大于 3的数是 : "<<*pr.second<<endl;
    23     return 0;
    24 }

     输出因该是这样的

    •  erase(iterator)  ,删除定位器iterator指向的值
    • erase(first,second),删除定位器first和second之间的值
    • erase(key_value),删除键值key_value的值

     

     1 #include<iostream>
     2 #include<set>
     3 using namespace std;
     4 int main()
     5 {
     6     set<int> s;
     7     set<int>::const_iterator iter;
     8     set<int>::iterator first;
     9     set<int>::iterator second;
    10     for(int i = 1 ; i <= 10 ; ++i)
    11     {
    12         s.insert(i);
    13     }
    14     //第一种删除
    15     s.erase(s.begin());
    16     //第二种删除
    17     first = s.begin();
    18     second = s.begin();
    19     second++;
    20     second++;
    21     s.erase(first,second);
    22     //第三种删除
    23     s.erase(8);
    24     cout<<"删除后 set 中元素是 :";
    25     for(iter = s.begin() ; iter != s.end() ; ++iter)
    26     {
    27         cout<<*iter<<" ";
    28     }
    29     cout<<endl;
    30     return 0;
    31     return 0;
    32 }

     

    输出

     

     

    • insert(key_value); 将key_value插入到set中 ,返回值是pair<set<int>::iterator,bool>,bool标志着插入是否成功,而iterator代表插入的位置,若key_value已经在set中,则iterator表示的key_value在set中的位置。
    • inset(first,second);将定位器first到second之间的元素插入到set中,返回值是void.

     

    • lower_bound(key_value) ,返回第一个大于等于key_value的定位器

     

    • upper_bound(key_value),返回最后一个大于key_value的定位器

    非常尴尬的发现就算学了这个东西,那题还是不会。。。。。。。

    STL(二)bitset

        感觉这个东西还挺好用的,也是STL里的一个神器,感觉好多题目都能用,那个三维偏序好像除了CDQ分治,KD——tree,和bitset都能打。。。还是只占一个字符,比单纯的bool,好用不知道多少。

    初始化:

     1 #include<iostream>
     2 #include<bitset>
     3 using namespace std;
     4 int main()
     5 {
     6     bitset<4> bitset1;//初始化,长度为4,全都是0 
     7     bitset<8> bitset2(12);//长度是8,用二进制存12,不足位补0 
     8     string s="10101";
     9     bitset<10> bitset3(s);//同上 
    10     cout<<bitset1<<endl;
    11     cout<<bitset2<<endl;
    12     cout<<bitset3<<endl;
    13     return 0;
    14 }

        输出应该是这样的:

    另外,bitset只能存0或1,如果有其他的东西会报错,原来char也可以,但不知道为什么会警告,能不用最好还是不用。。。。

    一些常见的位运算:

     1 #include<iostream>
     2 #include<bitset>
     3 using namespace std;
     4 int main()
     5 {
     6     bitset<4> bitset1(string("1100"));
     7     bitset<4> bitset2(string("0011"));
     8     cout<<(bitset1^=bitset2)<<endl;//按位异或后将值付给bitset1 
     9     cout<<(bitset1&=bitset2)<<endl;//按位与后将值付给bitset1 
    10     cout<<(bitset1|=bitset2)<<endl;//按位或后将值付给bitset1 
    11     cout<<(bitset1<<=2)<<endl;//右移后将值付给bitset1 
    12     cout<<(bitset1>>=1)<<endl;//左移后将值付给bitset1 
    13     cout<<(bitset1==bitset2)<<endl; //假的,返回false(0) 
    14     cout<<(bitset1!=bitset2)<<endl;//真的,返回true(1或-1)
    15     cout<<(bitset2&bitset1)<<endl;//左移后将值付给bitset1 ,其他同理 
    16     return 0;
    17 }

    输出应该是这样的:

    还可以像数组那样去访问每一位

    一些常用的函数:

    这正是STL吸引人的主要原因,可以不用手打,但会慢,对于我这样的蒟蒻就完全不会有影响,但也许对于机房旁边的大佬(传送门)就会有很大影响,这会让他AK不了IOI!!!!

    #include<iostream>
    #include<bitset>
    #include<cstdlib>
    #include<cstdio>
    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        bitset<8> bitset1(string("10111010"));
        cout<<bitset1.count()<<endl;//(count函数用来求bitset中1的位数,foo中共有5个1
        cout<<bitset1.size()<<endl;//(size函数用来求bitset的大小,一共有8位
        cout<<bitset1.test(0)<<endl;//(test函数用来查下标处的元素是0还是1,并返回false或true,此处foo[0]为1,返回true
        cout<<bitset1.test(2)<<endl;//(同理,foo[2]为0,返回false
        cout<<bitset1.any()<<endl;//(any函数检查bitset中是否有1
        cout<<bitset1.none()<<endl;//(none函数检查bitset中是否没有1
        cout<<bitset1.all()<<endl;//f(all函数检查bitset中是全部为1 
        //说明一下:test函数会对下标越界做出检查,而用过数组方式访问的元素则不会,所以用test更安全一些 
    
    string s=bitset1.to_string();//将bitset转换成string类型 unsigned long a=bitset1.to_ulong();//将bitset转换成unsigned long类型 cout<<s<<endl; cout<<a<<endl;
    cout
    <<bitset1.flip(2)<<endl;//(flip函数传参数时,用于将参数位取反,本行代码将foo下标2处"反转",即0变1,1变0 cout<<bitset1.flip()<<endl;//(flip函数不指定参数时,将bitset每一位全部取反 cout<<bitset1.set()<<endl;//(set函数不指定参数时,将bitset的每一位全部置为1 cout<<bitset1.set(3,0)<<endl;//(set函数指定两位参数时,将第一参数位的元素置为第二参数的值,本行对foo的操作相当于foo[3]=0 cout<<bitset1.set(3)<<endl; //(set函数只有一个参数时,将参数下标处置为1 cout<<bitset1.reset(4)<<endl;//(reset函数传一个参数时将参数下标处置为0 cout<<bitset1.reset()<<endl;//(reset函数不传参数时将bitset的每一位全部置为0 //这些函数同样会检查数组下标,有异常会提示。 return 0; }

     贪心:

    贪心是个非常有用的东西,有时候没有思路,也不会证明,但乱搞就过了。。。。

    bzoj 3668 起床困难综合征(

    • 从高位到低位枚举每一位,判断是1还是0,位运算各位之间不会影响。
    • 保证当前的数不会大于m;
    • 对于0能变为1的两种情况直接变。

    • 0变为的两种情况不予考虑。

    代码就非常简单:

     

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 const int maxn=1e5+10;
     5 char op[10];
     6 long long  n,m;
     7 long long  t;
     8 long long  ans=0,ans0=0,ans1=0x7fffffff;
     9 int main()
    10 {
    11     //freopen("testdata.in","r",stdin);
    12     scanf("%lld%lld",&n,&m);
    13     for(int i=1;i<=n;i++)
    14     {
    15         scanf("%s %lld",op,&t);
    16         if(op[0]=='A')
    17         {
    18             ans1&=t;
    19             ans0&=t;
    20         }
    21         else
    22         if(op[0]=='O')
    23         {
    24             ans1|=t;
    25             ans0|=t;
    26         }
    27         else
    28         if(op[0]=='X')
    29         {
    30             ans1^=t;
    31             ans0^=t;
    32         }
    33     }
    34     for(int i=30;i>=0;i--)
    35     {
    36         if(ans0&(1<<i))
    37         {
    38             ans+=(1<<i);
    39         }
    40         else
    41         if((m>=(1<<i))&&(ans1&(1<<i)))
    42         {
    43             m-=(1<<i);
    44             ans+=(1<<i);
    45         }
    46     }
    47     cout<<ans<<endl;
    48     return 0;
    49 }

     BZOJ 2563 阿狸和桃子的游戏(

    这题可以吧边权平分到两边的点,这样相对大小没变,一减也没变。

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=1e6+10;
     5 int sum[maxn];
     6 int x,y,z;
     7 int k;
     8 int ans=0;
     9 int n,m;
    10 int main()
    11 {
    12     cin>>n>>m;
    13     for(int i=1;i<=n;i++)
    14     {
    15         cin>>k;
    16         sum[i]=k<<1;
    17     }
    18     for(int i=1;i<=m;i++)
    19     {
    20         cin>>x>>y>>z;
    21         sum[x]+=z;
    22         sum[y]+=z;
    23     }
    24     sort(sum+1,sum+1+n);
    25     for(int i=n;i>=1;i-=2)
    26     {
    27         ans+=sum[i]-sum[i-1];
    28     }
    29     ans/=2;
    30     cout<<ans<<endl;
    31     return 0;
    32 }

     NOIP  2015 跳石头(还是回淮南的测试里的题目)

    •  显然这题这题就是二分还是比较经典的哪一类。
    • 二分一个答案,看他是否符合条件。
    • 贪心
    • 从第二块开始循环(第一块不能搬走,要不然你站哪?)假设现在到了第i块,上一个没搬走的是第J块,如果当前的距离小于ans,就可以直接搬走,要不然就留下来。
    • 最后一块不能搬走,要不你最后站哪?

    快乐的代码时光(机房考试还有人打了线段树,几千字。。。

     

     

     

     

     

          NOIP 2012 DAY2 T2 借教室

    • 这题好快乐,暴力拿了50分。。。
    • 正解还是二分,二分一个答案,看他能满足到哪一个订单。
    • 然后把1到ans的所有订单都扫描一下。
    • 可以用差分数组优化一下复杂度。

    代码

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<cstdlib>
     7 
     8 using namespace std;
     9 
    10 const int maxn=1e6+10;
    11 
    12 int need[maxn];
    13 int sheng[maxn];
    14 int r[maxn];
    15 int l[maxn];
    16 int d1[maxn];
    17 int d2[maxn];
    18 int n,m;
    19 
    20 int panduan(int x)
    21 {
    22     memset(d2,0,sizeof(d2));
    23     for(int i=1;i<=x;i++)
    24     {
    25          d2[l[i]]+=d1[i];
    26         d2[r[i]+1]-=d1[i]; 
    27     }
    28     for(int i=1;i<=n;i++)
    29     {
    30         need[i]=need[i-1]+d2[i];
    31         if(need[i]>sheng[i])
    32         return 0;
    33     }
    34     return 1;
    35 }
    36 
    37 int main()
    38 {
    39     memset(d1,0,sizeof(d1));
    40     memset(need,0,sizeof(need));
    41     memset(sheng,0,sizeof(sheng));
    42     memset(l,0,sizeof(l));
    43     memset(r,0,sizeof(r));
    44     cin>>n>>m;
    45     for(int i=1;i<=n;i++)
    46     {
    47         cin>>sheng[i];
    48     }
    49     for(int i=1;i<=m;i++)
    50     {
    51         cin>>d1[i]>>l[i]>>r[i];
    52     }
    53     if(panduan(m))
    54     {
    55         cout<<"0"<<endl;
    56         return 0;
    57     }
    58     else
    59     {
    60         int L=1,R=m;
    61         while(L<R)
    62         {
    63             int middle=(L+R)/2;
    64             if(panduan(middle))
    65             {
    66                 L=middle+1;
    67             }
    68             else
    69             {
    70                 R=middle;
    71             }
    72         }
    73         cout<<"-1"<<endl<<L<<endl;
    74     }
    75     return 0;
    76 }
  • 相关阅读:
    (转)A*算法详解及习题
    BZOJ1444[Jsoi2009]有趣的游戏——AC自动机+概率DP+矩阵乘法
    交通——set+dsu on tree
    [Codeforces1132G]Greedy Subsequences——线段树+单调栈
    BZOJ4482[Jsoi2015]套娃——贪心+set
    BZOJ4477[Jsoi2015]字符串树——可持久化trie树
    BZOJ4475[Jsoi2015]子集选取——递推(结论题)
    [UOJ86]mx的组合数——NTT+数位DP+原根与指标+卢卡斯定理
    BZOJ2428[HAOI2006]均分数据——模拟退火
    BZOJ4712洪水——动态DP+树链剖分+线段树
  • 原文地址:https://www.cnblogs.com/2529102757ab/p/11240694.html
Copyright © 2011-2022 走看看