训练日记 17.9.21

来源:互联网 发布:android源码下编译apk 编辑:程序博客网 时间:2024/06/05 04:54

这几天主要是看了一下上周末比赛的题目,看了第三题和第十题;

比赛的时候第一题要用到Java里面的高精度数

当时看到第三题,字符串匹配的,感觉是用kmp算法,但是没有写出来,这几天看了一下大神写的题解,发现可以用string自带的函数来解决,感觉自己知道的东西太少了;

用法是str1.find(str2)!=string::npos则表示字符串str2是str1的子串;

用这个函数的话代码就很好写了。

第十题给出一个序列,如果对于一个数a[ i ],每一次找出不满足a[ i-1 ]<=a[ i ]<=a[ i+1 ]的数删除,然后继续下一次查找和删除,知道序列不再减少。

看了一下大神的思路,就是每一次找的应该删除的数删除,然后下一次只需要查询上一次删除了的数的左右两方向的数是否应该删除,因为上一次删除数字后,影响的只能是删除数字左右两边的数字,所以这样查询。然后删除,重复进行下去。

这样的话我们需要申请两个队列一个储存上一次上出的数字,一个储存当前要删除的数字,我们要做一个操作循环利用两个队列。不然的话需要申请很多队列来实现。

对于删除环节在代码里面说明

下面是参考大神的代码:

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <iomanip>
#define N 100010
#define M 1000010//双倍
#define LL long long
#define inf 0x3f3f3f3f
#define lson l,mid,ans<<1
#define rson mid+1,r,ans<<1|1
#define getMid (l+r)>>1
#define movel ans<<1
#define mover ans<<1|1
using namespace std;
const LL mod = 1000000007;
struct node {
    int num;
    bool flag;//是不是删除了
    int next;//后继
    int pre;//前驱
}num[N];
int del[N];//堆栈
int main() {
    cin.sync_with_stdio(false);
    int n, T;
    cin >> T;
    while (T--) {
        cin >> n;
        queue<int> q[2];//两个队列,分别是存上一次删除的元素和当前要删除的元素,两个是要交替循环使用的使用异或实现
        for (int i = 1; i <= n; i++) {
            cin >> num[i].num;
            num[i].flag = true;
            if (i == 1) num[i].pre = -1;
            else num[i].pre = i - 1;
            if (i == n) num[i].next = -1;
            else num[i].next = i + 1;
        }
        int top = 0;
        for (int i = 1; i <= n; i++) {
            int num1 = num[i].pre;
            int num2 = num[i].next;
            if ((num1 != -1 && num[num1].num > num[i].num) || (num2 != -1 && num[num2].num < num[i].num)) {//相当与跑第一遍
                num[i].flag = false;
                del[top++] = i;//删除了哪个节点
                q[0].push(i);//记录删除了哪个节点
            }
        }
        for (int i = 0; i < top; i++) {
            num[num[del[i]].pre].next = num[del[i]].next;//删除节点
            num[num[del[i]].next].pre = num[del[i]].pre;
        }
        top = 0;
        int k = 0;
        while (!q[k].empty()) {//看看删除了后前后的点会不会删除
            while (!q[k].empty()) {
                int t = q[k].front();
                q[k].pop();
                int num1 = num[t].pre;//删除的节点的前驱结点
                int num2 = num[t].next;//删除的节点的后继结点
                int p1 = num[num1].pre;//删除节点的前驱的现在前驱节点
                int p2 = num[num1].next;//删除节点的前驱的现在后继节点
                if ((p1 != -1 && num[p1].num > num[num1].num) || (p2 != -1 && num[p2].num < num[num1].num)) {
                    if (num[num1].flag) {
                        num[num1].flag = false;//删除操作
                        del[top++] = num1;
                        q[k ^ 1].push(num1);
                    }
                }
                p1 = num[num2].pre;//删除节点的后继的现在前驱节点
                p2 = num[num2].next;//删除节点的前驱的现在前驱节点
                if ((p1 != -1 && num[p1].num > num[num2].num) || (p2 != -1 && num[p2].num < num[num2].num)) {
                    if (num[num2].flag) {
                        num[num2].flag = false;//删除操作
                        del[top++] = num2;
                        q[k ^ 1].push(num2);
                    }
                }
            }
            for (int i = 0; i < top; i++) {//把新删除的节点在链中删除掉
                num[num[del[i]].pre].next = num[del[i]].next;
                num[num[del[i]].next].pre = num[del[i]].pre;
            }
            top = 0;
            k = k ^ 1;//队列的转换,当前删除的元素下一次就变成了“上一次删除的元素",这样就实现了
        }
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            if (num[i].flag) {
                ans++;
            }
        }
        cout << ans << endl;
        for (int i = 1; i <= n; i++) {
            if (num[i].flag) {
                cout << num[i].num << " ";
            }
        }
        cout << endl;
    }
    return 0;
}

然后今天晚上有一场北京区域赛的赛前练习,看了一下题目,苦恼了半天,完全没什么思路。。感觉这周末的比赛也不会好做,可能又要水了。

原创粉丝点击