zoukankan      html  css  js  c++  java
  • 记五一清北(济南)

    Day 0

        下午15:00,告别了“留守”在学校的学长学姐及同学们,开始前往清北学堂(济南)。

        没想到,这车,一坐就是三个多小时,有种浑身酸痛的感觉。在车上,虽然没有电视看qwq, 但我们丝毫没有闲着,尤其是yjg 小朋友,不住嘴的吃。

        1800多(多多少忘记了 2333)终于来到听YYFHMQ说过很多次的“如驿酒店”。看外观好像还不错的样子,里面怎么样就不知道了。

        安排房间,吃饭。我跟小学妹的房间在一楼,然后,我们就在里面绕啊绕@_@,好不容易找到房间,结果又换掉了 2333,重新开始找。不过新房间(二楼的)好像要稍微大那么一丢丢(虽然远不及寒假青岛的,但胜在便宜啊T_T)。

        吃饭是在老师念叨很久的“超意兴”,有点自助餐的感觉。话说那个 把子肉 好好吃,不过我就吃了一次   (¯﹃¯)


    Day 1 + Day 2

       学习内容:

          1.排序 

        冒泡排序:这个比较基础,早就听过两遍了,简单说就是 两两交换

    /*
    数组中逆序对较少时
    */
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    int a[1000];
    int n = 20;
    
    void sort(int *a, int l, int r) {
        for(int i = l; i <= r; i++)
            for(int j = l; j <= r; j++)
                if(a[j] > a[j+1]) swap(a[j], a[j+1]);
    }
    
    int main() {
        sort(a, 0, n-1);
        for(int i = 0; i < n; i++) printf("%d ", a[i]);
        return 0;
    }
    冒泡排序

        插入排序:应用于在线算法,挺好用的,而且之前做题也见过 (好像忘记记代码了 2333)

        快速排序(即c++中的sort):有人说:这个有什么好学的啊,但是我们还是在调用sort的时候多想一下它的核心内涵吧

    /*
    快速排序 及 其应用——快速选择 
    */
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    int n, k;
    int a[1000];
    
    void sort(int *a, int l, int r) {
    //时间复杂度 递归式T(n) = O(n) + 2*T(n)
    //即 O(nlogn) 
        swap(a[l], a[rand()*rand()%(r-l+1)+l]);
        int tmp = a[l];    //右边的元素均小于tmp,左边的元素均大于tmp 
        int l_ = l, r_ = r;
        while(l < r) {    //循环的时间复杂度为区间长度 
            while(l < r) {
                if(a[r] > tmp) r--;    //a[r]落在正确的位置,不需要被调整 
                else { a[l++] = a[r]; break; }
            }
            while(l < r) {
                if(a[l] < tmp) l++;    //同上 
                else { a[r--] = a[l]; break; }
            }
        }
        a[l] = tmp;
        if(l-l_ > 1) sort(a, l_, l-1);
        if(r-r_ > 1) sort(a, r+1, r_);
    }
    int select(int *a, int l, int r, int k) {
        swap(a[l], a[rand()*rand()%(r-l+1)+l]);
        int tmp = a[l];
        int l_ = l, r_ = r;
        while(l < r) {
            while(l < r) {
                if(a[r] > tmp) r--;    //a[r]落在正确的位置,不需要被调整 
                else { a[l++] = a[r]; break; }
            }
            while(l < r) {
                if(a[l] < tmp) l++;    //同上 
                else { a[r--] = a[l]; break; }
            }
        }
        a[l] = tmp;
        if(k == l-l_+1) return a[l];
        if(k < l-l_+1) return select(a, l_, l-1, k);    //比较tmp左边的元素 
        if(k > l-l_+1) return select(a, r+1, r_, k-(l-l_+1));    //比较tmp右边的元素 
    }
    
    int main() {
        sort(a, 0, n-1);
        select(a, 0, n-1, k);    //寻找第k小的元素 
        for(int i = 0; i < n; i++) printf("%d ", a[i]);
        return 0; 
    }
    /*
    选择排序:T(n) = O(n) + T(n/2)
    T(n) = O(n)
    
    n = 2^k
    2^k+2^(k-2)+2^(k-2)+...+1 = 2*2^k = 
    */
    快速排序及其应用——快速选择

        归并排序:核心思想为二分,所以它的时间复杂度是log级别的,也可以用于求逆序对

    /*
    可用于求逆序对 
    会多开一倍空间,且比较慢 
    */
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    int n;
    int a[1000], b[1000];    //b[]为辅助数组 
    
    void sort(int *a, int l, int r) {
        if(l == r) return ;
        int mid = (l+r) >> 1;
        sort(a, l, mid);
        sort(a, mid+1, r);
        
        int i = l, j = mid+1;
        for(int k = l; k <= r; k++) {
            if(j>r || (a[i]<a[j] && i<=mid)) {
                b[k] = a[i];
                i++;
                //求逆序对个数 
                //ans += j-(mid+1)
            }
            else {
                b[k] = a[j];
                j++;
            }
        }
        for(int k = l; k <= r; k++) a[k] = b[k];
    }
    
    
    int main() {
        sort(a, 0, n-1);
        for(int i = 0; i < n; i++) printf("%d ", a[i]);
    //    printf("%d", ans);
        return 0;
    }
    归并排序

          2.快速幂

        话说我们刚学,下午考试就用到了它的亲戚:快速乘,比高精还快了 0.1 second   哈哈

    /*
    快速幂
        整数
        矩阵
        多项式
        支持 a - a 运算 
            a是一个排列,- 是一种自定义的运算,表示a[a[x]] 
    */ 
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    int a = 5, x = 7;
    
    int pow(int a, int x) {    //核心
        int ans = 1;
        for(int now = a; x; x >= 1, now = now*now)
            if(x & 1) ans *= now;
        return ans;
    }
    
    
    int main() {
        printf("%d", pow(a, x));
    }
    快速幂

          3.高精

        为什么有高精呢?因为有些数是会爆 long long 滴,所以我们选择把这些数作为字符串(或字符数组)储存起来

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    string s;
    
    struct bignum {    //暂时不能处理负数 
        int n;
        int a[500];
        //int f; 用于处理负数 
        bignum() {
            n = 0;
            memset(a, 0, sizeof(a));
        }
        bignum(string s) {
            n = s.size();
            memset(a, 0, sizeof(a));
            for(int i = 0; i < n; i++) a[i] = s[n-1-i]-'0';
        }
        bignum(int s) {
            memset(a, 0, sizeof(a));
            n = 0;
            while(s > 0) {
                a[n] = s%10;
                s /= 10;
                n++;
            }
        }
        void work() {
            for(int i = 0; i < n; i++) {
                if(a[i] < 0) {
                    int tmp = (-a[i] - 1) / 10 + 1;
                    a[i] += 10*tmp;
                    a[i+1] -= tmp;
                }
                if(a[i] >= 10) {
                    int tmp = a[i] / 10 + 1;
                    a[i] -= 10*tmp;
                    a[i+1] += tmp;
                    if(i==n-1 && a[i+1]>0) n++;
                }
            }
            while(n>0 && !a[n-1]) n--;
        }
        void print() {
            for(int i = n-1; i >=0; i--)
                cout << a[i];
            cout << '
    ';
        }
    };
    
    bignum operator + (const bignum &a, const bignum &b) {
        bignum c;
        c.n = max(a.n, b.n);
        for(int i = 0; i < c.n; i++)
            c.a[i] = a.a[i]+b.a[i];
        c.work();
        return c;
    }
    bignum operator - (const bignum &a, const bignum &b) {
        bignum c;
        c.n = max(a.n, b.n);
        for(int i = 0; i < c.n; i++)
            c.a[i] = a.a[i]-b.a[i];
        c.work();
        return c;
    }
    bignum operator * (const bignum &a, const bignum &b) {
        bignum c;
        c.n = max(a.n, b.n);
        for(int i = 0; i < a.n; i++)
            for(int j = 0; j < b.n; j++)
                c.a[i-j] += a.a[i]*b.a[i];
        c.work();
        return c;
    }
    
    int main() {
        cin >> s;
        int x;
        cin >> x;
        bignum a(s);
        bignum b(x);
        (a+b).print();
        (a-b).print();
        (a*b).print();
        return 0;
    } 
    高精(话说当时跟着老师敲好累,可能会有一些错的地方2333)

          4.搜索

        这个老师没这么讲,反正意思就是:你们天天写的暴力就差不多,不用多讲 2333

          5.二分

        二分法主要指通过二分某个参数的值,并快速判断二分值是偏大或偏小,进而调整下一个二分的值。 

        二分法的核心在于寻找“单调性”——随着待二分的值增大或减小,计算出的检测值应该是单调的。当二分到合适的位置,检测值应该与期望情况相符。

    /*
    头文件们
    
    */
    
    
    int binary_search(int x)
    {
        int l = 1, r = n;
        while (l < r)
        {
            int mid = (l + r) >> 1;
            if (a[mid] <= x) l = mid + 1;
            else r = mid;
        }
        //在a数组中,大于x的最小的整数 
        //a[l] == x?
    }
    
    int binary_search(int x)//数列分段-二分部分 
    {
        int l = l0, r = r0;
        while (l < r)
        {
            int mid = (l + r) >> 1;
            int ret = check(mid);//check(mid)返回最大值设为mid的时候的最小段
    if (ret > m) l = mid + 1;
            else r = mid; 
            
        }
        //求出的l即为答案 
    }
    二分

          6.倍增

        倍增与二分法刚好相反——二分法通过不断将取值区间缩半来缩小取值的可能范围,而倍增法通过将考虑规模不断乘二来拓展维护的范围。

        倍增法的一个最经典的应用是求解RMQ问题。即给定一个长度为n的序列,多次询问某个区间的最大值。 具体做法是:对于序列中的某个元素,记录下这个元素往后+1,+2,…,+2^p内的元素中的最大值。这一部分信息可以在O(nlogn)的时间内更新完成。 回答一次询问时,一个区间的最大值可以通过求两个长度恰好为2^p的区间的最大值的最大值来得到,因此单次回答的复杂度为O(1)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    using namespace std;
    
    int fpow(int a, int x)  //核心代码
    {
        int ans = 1;
        for (int now = a; x; x >>= 1, now = now * now)
            if (x&1) ans = ans * now;
        return ans;        
    }
      
    
    int main()
    {
        
        int a = 5, x = 7;
        cout << fpow(a, x) << endl;
    }
    倍增

          7.其他一些技巧

        (1)差分与前缀和

        (2)均摊分析

        (3)贪心

        (4)分治

      Day 1 的考试详见:http://www.cnblogs.com/v-vip/p/8971880.html


    Day 3 + Day 4

      话说(@@)~

      学习内容:

          Day 3   今天讲的我好像之前都会呢  qwq ,听起来很顺

        图的基本知识   理解了就记住了

        图的储存——邻接链表、邻接矩阵    理解的基础上,记代码

        最短路:  Dijkstra+堆优化、spfa+SLF优化、spfa判负环、Floyd

        最小生成树: Prim (稠密图)、 Kruskal (稀疏图)

        拓扑排序   第三遍听。。。

        强连通分量   要用到著名的 Tarjan 算法,像缩点、求LCA什么的。。。

        然后是成堆的例题。。。。

          Day 4   一整天,除了讲STL之外,整个人都是 懵的 2333    这是为什么呢?因为我们在讲数论。。。

        具体的定理、算法我就不说了, so many。。。

        下面粘一下抄的STL的笔记

    using namespace std;
    
    
    
    #include<algorithm>
    
    int a[100];//[1, 99]
    int b[100];
    struct nond {
        int x, y;
        bool operator <(const nond &rhs) const{
            if(x == rhs.x) return y < rhs.y;
            return x < rhs.x;
        }
    }e[100];
    
    
        for(int i = 1; i <= n; i++) a[i] = i;
        sort(&a[1], &a[100], cmp) //sort( , &a[99]+1, )
        int a = unique(&a[1], &a[10]) - a;//数组必须有序
        
    //
    
    void f(int *a, int n);//....
    
        
        for(int i = 1; i <= n; i++)
        while(next_permutation(&a[1], &a[n]+1)) {
            f(a, n);
        }
        
    //
    lower_bound(&a[1], &a[n]+1, x); //>=x
    upper_bound(&a[1], &a[n]+1, x); //>x 
        
    #include<utility>
    
    
    pair<int, int> p;
    p.first, p.second;    
    //    
    make_pair(1, 2);
        
    #include<iostream>
    
    cin; cout ; cerr;
    //stdin, stdout, stderr
    #include<ios>
    ios::sync_with_stdio(false); //加速cin, cout 
    #include<iomanip>
    cout << fixed << setprecision(8) << f;
    //相当于 printf("%.8f", f); 
    
    #include<set>
    #include<map>
    #include<multiset>
    
    set<int> s;
    set<int>::iterator it;//set 迭代器 
    s.lower_bound(x);//>=x
    s.upper_bound(x);//>x
    s.insert(x);
    it = s.find(x);
    if(it == s.end()/*数组最后一个元素之后的一个*/) {
        *it;
    } 
    for(it = s.begin(); it != s.end(); it++){
         *it;
    }
    
    map<int, int> h;
    h[1] = 2;
    map<string, int> h; //set<pair<string, int> >
    h['a'] = 1;
    h["aaab"] = 2;
    map<string, it>::iterator it2;
    it2 = h.find("aaab");
    it2->first == "aaab";
    it2->second == 2;
    
    
    
    multiset<int> s;
    //允许重复元素,而set不允许重复元素 
    
    
    #include<string>
    
    string s = "342342423fa";
    s.substr(1, 10); //[1, 11]
    s += "abcd";
    
    #include<vector>
    vector<int> a;
    for(int i = 0; i < 100000; i++) a.push_back(i);
    
    a.pop_back();
    a[10], a[100];
    
    
    struct nond {
        int node, w;
    }; 
    vector<nond> e[N];
    
    void add(int a, int b, int w) {
        e[a].push_back({b, w});
    }
    for(int i = 0; i < e[x].size(); i++) {
        int node = e[x][i].node;
    }
    for(vctor<nond>::iterator it = e[x].begin(); it != e[x].end(); it++) {
        int node = it->node;
    }
    
    //c++11
    auto it = e[x].begin();//vctor<nond>::iterator
    for(auto it : e[x]) {
        int node = it->node;
    }
    
    
    
    #include<queue>
    
    struct nond {
        int d, i;
        bool operator <(const nond &rhs) const {
            return d > rhs.d;
        }
    };
    pririty_queue<nond> q;
    
    struct node {
        int d, i;
        bool operator <(const node &rhs) const {
            return d < rhs.d;
        }
    };
    priority_queue<node, vector<node>, greater<node> > q;
    STL

    Day 5 + Day 6

        Day 5  主讲数据结构  兴奋

          单调栈、单调队列   已经用的比较熟练了

          二叉堆   嗯....好像跟二叉树差不多

          堆的应用:Prim、Kruskal优化 or  堆排序

          并查集   这个应该往图论里算吧。。。

          树状数组   类似于线段树,不过不如线段树好理解

          RMQ   静态(无法修改)求区间的最大/最小值,而利用倍增的ST表可以很好地解决这个问题

          二叉搜索树   支持元素插入,查询前驱、后继、排名

          线段树    二分实现,用于单点/区间  修改/查询,代码易懂

        Day 6  动态规划(DP)

          1.数字三角形

            枚举 → 记忆化搜索 → 状态转移方程

          2.最长上升子序列(LIS)

            从数列中找出的数列满足 当 i < j 时, a[i] < a[j] 且  最长

          3.最长公共子序列(LCS)

            分别从两个数列中选出一些数,构成另外两个序列,且新的两个序列保证 i = j 时, a[i] = a[j] 且  最长

          4.区间动规

            当遇到环形情况时,可以通过将序列加倍的方法来用动规做

          5.背包

            完全背包、0/1背包、多重背包   这里不多介绍

          6.树上动规

            基础:求树的直径、树的重心


    Day 7 + Day 8

       这两天讲课的是贪心大神 CCL,但是他并不给我们讲贪心

       唉,有点遗憾,不过经常上着课就会有人起哄:“讲贪心,讲贪心”,还是挺有意思的

       最有趣的要数老师的口音了,不知道是哪里的;讲课、讲题时很搞笑,但是思路清晰、易懂,逐步深入

         Day 7   主讲:字符串

          1.字符串的储存及基本操作

          2.KMP算法

            暴力枚举 or KMP算法   求字符串B在字符串A中出现了几次 (B <= A)可转化为求 f[i]

            用两个指针不断“跳”

          3.Trie 树

            支持插入、查询操作,可查询前缀出现次数、最长前缀、单词等

            注意:Trie 树 的根为空;时间复杂度低

          4.Hash 哈希

            通过比较哈希值是否相等来比较两个字符串是否相等,有概率出错(不过很小哦)

            选取基底作为被mod的数(一定要比字符种类多,最好是质数且不要太常见,万一出题人就卡你这个呢 qwq),将每个字符看做数字,然后进行取模运算。

          5.后缀数组


            呐呐,还想吃那里的紫菜包饭,楼下的“开水泡馍”和烩面,还想吃烧烤,喝暖暖的奶茶,还想.....

  • 相关阅读:
    ASP.NET Web应用程序与ASP.NET Web服务应用程序的区别
    【你必须知道的.NET】:【大话String】
    获取SQLServer数据库中所有表
    Window_Open详解收藏
    关于数据实现批量删除
    asp.net mvc 图形解析说明原理
    【转载】:C#语言
    泛型参数的约束
    SQL 常用函数小结
    [转载]:C#两种不同的存储过程调用方法
  • 原文地址:https://www.cnblogs.com/v-vip/p/9029278.html
Copyright © 2011-2022 走看看