• 杂题


    高精度计算

    在NOIP里,一般只涉及大整数的运算

    (int)(-2^{31})~(2^{31}-1)

    (longspace long)(-2^{63})~(2^{63}-1)

    如何表示更大范围的整数?(A=overline{a_{l-1}a_{l-2}dots a_0}=acdot10^0+a_1cdot10^1+...+a_{l-1}cdot10^{l-1})

    字符串输入,倒序转换(毒瘤题(压空间的)需要压位,如每4位放进一个int。但一般一位一个int足矣)

    加法&减法

    模拟竖式计算过程即可,注意:

    进退位为(pm1)

    注意处理最高位以及进位

    高精度乘法

    • 大数乘大数

      同理,(XY=sum_{i=0}^{l_x-1}sum_{j=0}^{l_y-1}x_iy_j10^{i+j})

      乘完的长度不超过 (X)(Y)的长度之和

    • 大数乘小数

      个位一次性乘完再处理进位即可

    二分

    注意事项:

    • 二分是对有关有序数列的操作
    • 区间的更新方式与终止条件 经常犯错 要考虑完善,

    二分查找

    int BinarySearch(int l,int r,int t,int x[]) {
        while(l<=r) {
            int mid=(l+r)>>1;
            if(x[mid]==t) {
                return mid;
            } else if(x[mid]<t) {
                l=mid+1;
            } else {
                r=mid-1;
            }
        }
        if(l>r) {
            return -1;
        }
    }
    

    函数复杂度(O(log_2n))

    二分答案

    判断条件:

    1. 问题的答案满足单调性
    2. 题目要求最大最小等

    解决套路:

    1. 把可能的答案序列排序
    2. 枚举当前可能的答案区间中间值mid
    3. 验证这个答案是不是一个可行解
    4. 缩小区间,重复2
    5. 缩小到不能二分时,判断是无解还是找到了最优可行解

    字符串

    字符串术语

    • 子序列(不破坏相对顺序)、子串(连续的字符的集合,个数(=frac{n(n+1)}{2})),回文串

    • 前缀,后缀

    • 字符串匹配

      在文本串(T)(或集合)中,找到所有与模式串(P)匹配的个数

    Trie树

    解决:

    • 字符串匹配
    • 前缀匹配

    基本性质:

    • 储存了字符串的前缀信息

    • 除了根节点,其他节点有且仅有一个字符

    • 从根节点开始到某一个节点连接起来就是该节点对应的前缀

    • Trie树可以在线构建

    • 插入一个新的字符串

      • 时间复杂度(O(len))
      • 空间复杂度(O(sum len))

    用法:

    • 字符串查找
    • 前缀相同的字符串
    • 自动排序
    • 两两计算最长公共前缀
    • 扩展:建二进制Trie树,存二进制数

    存储实现:

    struct Node {
        int cnt;
        Node *ch[30]= {0};
        //或者
        int nxt[30]= {0};//转指针为数组
    };
    

    字符串Hash

    (该算法如果想被卡比较容易,所以不推荐

    字符串( ightarrow)数字:

    hash=0;
    p=19260817LL,q=1e9+7LL;
    for(int i=0; i<len; i++) {
        hash=(hash*p%q+s[i]-'a'+1)%q;
    }
    

    KMP算法

    • 加速单模板串,多个文本串或长文本串的匹配

    失配数组(nxt数组)

    • 失配数组(nxt[i]=j)表示当第(i)位失配时可以快速移动到(j)

    • (nxt)数组代可以通过自己配对自己得到

    •   void getnext(char *s,int len,int *nxt) {
            int x=0;
            nxt[0]=-1;
            for(int i=1; i<len; i++) {
                while(x!=-1&&s[x]^s[x-1]) {
                    x=nxt[x];
                }
                nxt[i+1]=++x;
            }
        }
        //kmp函数同理
      

    马拉车

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 5;
    char s[maxn * 2], str[maxn * 2];
    int Len[maxn * 2], len;
    void getstr() {//重定义字符串
    	int k = 0;
    	str[k++] = '@';//开头加个特殊字符防止越界
    	for (int i = 0; i < len; i++) {
    		str[k++] = '#';
    		str[k++] = s[i];
    	}
    	str[k++] = '#';
    	len = k;
    	str[k] = 0;//字符串尾设置为0,防止越界
    }
    int manacher() {
    	int mx = 0, id;//mx为最右边,id为中心点
    	int maxx = 0;
    	for (int i = 1; i < len; i++) {
    		if (mx > i) Len[i] = min(mx - i, Len[2 * id - i]);//判断当前点超没超过mx
    		else Len[i] = 1;//超过了就让他等于1,之后再进行查找
    		while (str[i + Len[i]] == str[i - Len[i]]) Len[i]++;//判断当前点是不是最长回文子串,不断的向右扩展
    		if (Len[i] + i > mx) {//更新mx
    			mx = Len[i] + i;
    			id = i;//更新中间点
    			maxx = max(maxx, Len[i]);//最长回文字串长度
    		}
    	}
    	return (maxx - 1);
    }
    int main() {
    	scanf("%s", s);
    	len = strlen(s);
    	getstr();
    	printf("%d
    ",manacher());
    	return 0;
    }
    

    题目

    例题

    1. CF1181B

      从中间开始向两边找,找到第一个划分即为所求

    2. CF900B

      模拟(e.g (frac{24}{7}:(24,0) ightarrow(3,3) ightarrow(30,3)...)

    3. AT2827

      贪心+二分查找优化时间复杂度

    4. P2678

      二分选手的最小跳跃距离,如果距离小于选手的最小跳跃距离则把这块石头移走,移走数目大于(m)时不满足题意,反之亦然。

    推荐练习

    P2954,P1631,HDU1358 Period,HDU2203,SP7586

    知识共享许可协议

    本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

    限于本人水平,如果文章有表述不当之处,还请不吝赐教。

  • 相关阅读:
    javaScript 事件循环机制
    javaScript 原型与原型链
    清除浮动
    水平垂直居中的实现
    GitLab + Jenkins + Harbor 工具链快速落地指南
    a标签下载存储在项目中的文件
    判断数组对象中某一属性是否包含重复的值
    网站title前的小图标
    给二维数组动态赋值
    格式化eltable中的时间
  • 原文地址:https://www.cnblogs.com/Sam2007/p/12409142.html
Copyright © 2020-2023  润新知