新生赛以后就正式成为一名acmer啦 ~虽然没有打过比赛呜呜呜

要好好学算法,拿一个牌牌嘛~

这里就记录算法学习情况,也怕自己偷懒,学一个就记录,看看长时间拖更就是在摸鱼,摸鱼和鸽子都是本质 ,加油!

开坑时间 2020.12.9

2020.12.9 今日快排走起(加模板)

quicksort!

void quicksort(ll a[],ll l,ll r)
{
if(l>r) return ; //递归跳出条件 ll temp=a[l]; ll i=l; ll j=r; //基准态定义和l,r定义 while(i!=j) //i,j不碰头
{
while(a[j]>=temp&&i<j) j--; //注意i<j条件,不然存在相等的数就无法跳出循环
while(a[i]<=temp&&i<j) i++; //同上
if(i<j) swap(a[i],a[j]);
} a[l]=a[i]; //基准态交换
a[i]=temp; quicksort(a,l,i-1); //递归
quicksort(a,i+1,r);
}

快排是分治的思想,设定一个基准态,将比基准态小的数放在左边,将比基准态大的数放在后边,然后将基准态归位,完成一个调整,这样一来部分数顺序已经调整,在分成左右区间进去递归,重复上述过程,已经归位的基准态不用管,(l,i-1)和(i+1,r)进行下一步递归,此时i为已经归位的数不需要再次递归。

个人理解: 快排原理是根据已经排好的数有一个规律:比n小的在n左边,比n大的在n的右边,所以左右遍历调整错误顺序数的位置,最后遍历完后(i==j)时,左右均已经遍历完,此时基准态归位完成一个循环,再进行区间二分,进行递归。

时间复杂度: 平均O(n)=nlogn,最坏的情况会退化到O(n)=n^2,最好情况也是O(n)=nlogn.

sort大法好


2020.12.10 分治里面归并少不了

mergesort!

int temp[200000];   //归并需要额外的空间存放调整完后的数据
void merge_sort(int q[], int l, int r)
{
if(l>=r) return; int mid=l+r >> 1; merge_sort(q,l,mid) , merge_sort(q,mid+1,r); //分解 // 调整顺序
int k=0, i=l, j=mid+1;
while(i<=mid&&j<=r)
if(q[i]<=q[j]) temp[k++]=q[i++];
else temp[k++]=q[j++];
while(i<=mid) temp[k++]=q[i++];
while(j<=r) temp[k++]=q[j++]; for(i=l,j=0;i<=r;i++,j++) q[i]=temp[j];
}

y总的一个函数完成归并模板orz 记录一下

归并排序:思路也是分治思想,先分成若干小部分,在单独递归处理后,合并在一起。为了满足数组有序,我们可以一直二分到子数组只有两个数,在一个个调整顺序,最后左右两边实行最后一次合并到另外一个数组中,完成所有排序。如下图:



调整顺序中: 用两个指针指向两个子数组的头,相互比较,把较小的数存在temp数组中,然后把指向原数的指针向后移动一位,继续比较重复上述过程,如果某个指针到头了,就把另外剩下的数全部补在temp数组中完成一次调整顺序,最后把temp数组中的数据移动在需要排序的数组中即可。

确实很强呐呜呜呜


2020.12.12 二分查找板子来一个~

half_find!

自己的中式英语

binary_find

别问11号干嘛去了,问就是摸鱼去了 (比赛加摸鱼)

int half_find(int a[],int l,int r,int b)
{
while(l<r)
{
int mid=l+r >>1;
if(a[mid]>b) r=mid; //这里判断条件改动与lower_bound和upper_bound用法一致
else l=mid+1;
}
return l;
}

二分的板子边界一堆,直接记忆这个 实在不行stl大法好嘛 ,尽量自己写呐,简单的板子好记,原理也简单,记住if后不加,else后加1就行~,主要是边界问题难受最后return l和r一样的,因为此时l==r。

y总yyds


2020.12.14 静态链表(单链表)(数据结构冲冲冲)

Linked_list(Static)!

别问...13号干嘛去 gugugu 湖南停电停水大学实锤

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#define int ll
#define ll long long
using namespace std; ll val[200000];
ll p[200000];
ll idx;
ll head; void init() //创建静态单链表
{
head=-1;
idx=0;
} void head_add(ll x) //在head处插入结点
{
val[idx]=x,p[idx]=head;
head=idx++;
} void nor_add(ll k,ll x) //在k处插入一个结点
{
val[idx]=x,p[idx]=p[k];
p[k]=idx++;
} void nor_remove(ll k) //把k后的一个结点删除
{
p[k]=p[p[k]]; //p[k++]不对注意!
} void head_remove()
{
head=p[head];
}
ll n;
ll x,y;
char a;
signed main()
{
cin>>n;
init();
while(n--)
{
cin>>a;
if(a=='H')
{
cin>>x;
head_add(x);
}
else if(a=='D')
{
cin>>x;
if(x) nor_remove(x-1);
else head_remove();
}
else if(a=='I')
{
cin>>x>>y;
nor_add(x-1,y);
}
}
for(int i=head;i!=-1;i=p[i])
{
cout<<val[i]<<" ";
}
cout<<endl;
return 0;
}

原题链接acwing的~

总结一下所谓静态链表:用数组模拟链表(原因: 动态链表非常非常耗时间,malloc和new速度很慢,对acmer很不友好),用双数组模拟链表,实现某些功能(树图警告),val表示实际存入的值,p表示下一个数的下标(等价于链表),再加上一个head表示头指针,idx表示剩余空间的第一位下标,可调用,创建新结点)(又是一个用空间换时间的呜呜呜)

几种基本操作:

1.创建新链表

void init()  //创建静态单链表
{
head=-1;
idx=0;
}

将head指向-1(表示null),idx=0表示数组均可用。

2.添加结点

void head_add(ll x)  //在head处插入结点
{
val[idx]=x,p[idx]=head;
head=idx++;
} void nor_add(ll k,ll x) //在k处插入一个结点
{
val[idx]=x,p[idx]=p[k];
p[k]=idx++;
}

插入要分头插其他结点插

头插需要修改head,其他就不要需分开

先创建一个结点,再将创建的结点指向k或者头指向的那一位,最后将头或者k指向创建的数组, 记住idx要++ 这一步与上一步可以合并(因为可用的已经用了一位idx要往后移一位)

3.删除结点

void nor_remove(ll k)   //把k后的一个结点删除
{
p[k]=p[p[k]]; //p[k++]不对注意!
} void head_remove()
{
head=p[head];
}

同理删除也要分头和其他y总翻车现场 还是head的问题,这里注意,代码里面有注意的,不能写成p[k++]因为有时候k++不一定是k后面那一位,要用p[p[k]]表示k后面那一位,与指针类似。

4.链表遍历

for(int i=head;i!=-1;i=p[i])  cout<<val[i]<<" ";

从head开始顺着p开始遍历,如果i==-1(即此时遇到尾结点,跳出循环),同样注意,后面不是i++,而是把p[k]给i,表示指针后移一位。

就这样自己晚个安 绝对不熬夜


2020.12.15 双链表!

#include<bits/stdc++.h>
#define int ll
#define ll long long
using namespace std;
const int N = 2e6;
ll val[N], l[N], r[N],idx;
ll m; void init()
{
r[0]=1,l[1]=0;
idx=2;
} void add(int k,int x) //k后
{
val[idx]=x,r[idx]=r[k],l[idx]=k;
l[r[k]]=idx,r[k]=idx++;
} void remove(int k) //删除第k个点
{
r[l[k]]=r[k];
l[r[k]]=l[k];
} signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
init();
cin>>m;
while(m--)
{
string a;
int k,x;
cin>>a;
if(a=="L")
{
cin>>x;
add(0,x);
}
else if(a=="R")
{
cin>>x;
add(l[1],x);
}
else if(a=="D")
{
cin>>k;
remove(k+1);
}
else if(a=="IL")
{
cin>>k>>x;
add(l[k+1],x);
}
else if(a=="IR")
{
cin>>k>>x;
add(k+1,x);
}
}
for(int i=r[0];i!=1;i=r[i]) cout<<val[i]<<" ";
cout<<endl;
return 0;
}

双链表: 一个结点同时有指向左右两边的指针,L[]和R[],没有头指针,将0,1分别做为链表的头尾。不含其他实际数值,在0,1之间插入删除,其他与单链表类似。注意双向都要考虑.

最后注意: 链表中不要出现++操作。要用指针,也就是数组对下一位进行操作,用R[]表示下一位,L[]表示上一位。

over~


2021.1.3新年快乐...~ gugugu

我,大鸽子,来更新了~ (逃

来一个快速幂板子和费马小定理

快速幂板子

ll qpow(ll a, ll x)
{
ll re = 1;
while(x)
{
if(x&1) re = re * a % M;
a = a * a % M;
x = x >> 1;
}
return re;
}

M为防止数太大除的余数,a为底数,x为指数,思想跟二分差不多,将质数一次循环就除二,底数自己乘一次减少计算机次数。

费马小定理

原公式: a ^ (p-1) = 1 (mod)

费马小定理主要是防止指数太大时,如果是求同余的数,可以大大减少指数的大小

升级公式 : ( a ^ n ) % p = ( a ^ ( n % (p -1) ) % p )

也就是当n很大的时候,若p是质数, a 与p互质 , n可以先与(p-1)取模以后再进行整体%P,因为两数同余,结果一样。


2021.1.10别问,问就是期末考试 咕咕咕

高精度板子整理

高精度加法

#include<bits/stdc++.h>
#define fp for(int i=1;i<=n;i++)
#define ll long long
using namespace std; vector<ll> add(vector<ll> &A , vector<ll> &B)
{
ll lena=A.size();
ll lenb=B.size();
vector<ll> C;
ll t=0;
for(int i=0;i<lena||i<lenb;i++)
{
if(i<lena) t+=A[i];
if(i<lenb) t+=B[i];
C.push_back(t%10);
t/=10;
}
if(t) C.push_back(1);
return C;
} int main()
{
string a,b;
vector<ll> A,B,C;
cin>>a>>b;
ll lena=a.size();
ll lenb=b.size();
for(int i=lena-1;i>=0;i--) A.push_back(a[i]-'0');
for(int i=lenb-1;i>=0;i--) B.push_back(b[i]-'0');
C=add(A,B);
ll lenc=C.size();
for(int i=lenc-1;i>=0;i--) cout<<C[i];
cout<<endl;
return 0;
}

用vector代替数组,因为有个size函数,方便操作,函数里面t有多重身份注意。

高精度减法

#include<bits/stdc++.h>
#define ll long long
#define s size()
#define pb push_back
#define vl vector<ll>
using namespace std; bool cmp(vl &a,vl &b)
{
if(a.s!=b.s) return a.s>b.s;
for(int i=a.s-1;i>=0;i--)
if(a[i]!=b[i]) return a[i]>b[i];
return true;
} vl sub(vl &a,vl &b)
{
ll lena=a.s;
vl c;
for(int i=0,t=0;i<lena;i++)
{
t=a[i]-t;
if(i<b.s) t-=b[i];
c.pb((t+10)%10);
if(t<0) t=1;
else t=0;
}
while(c.s>1&&c.back()==0) c.pop_back();
return c;
}
int main()
{
string A,B;
vl a,b,c;
cin>>A>>B;
ll lena=A.s;
ll lenb=B.s;
for(int i=lena-1;i>=0;i--) a.pb(A[i]-'0');
for(int i=lenb-1;i>=0;i--) b.pb(B[i]-'0'); if(cmp(a,b))
{
c=sub(a,b);
ll lenc=c.s;
for(int i=lenc-1;i>=0;i--) cout<<c[i];
cout<<endl;
}
else
{
c=sub(b,a);
ll lenc=c.s;
cout<<"-";
for(int i=lenc-1;i>=0;i--) cout<<c[i];
cout<<endl;
}
return 0;
}

减法的话要先判断减数和被减数的大小,先决定输出+,-号,(该代码未考虑负数的相减),然后通过cmp控制大的为被减数,再最后注意借位问题就好啦。

还要注意去掉前导0.

高精度乘法

先是高精度×小数

#include<bits/stdc++.h>
#define s size()
#define pb push_back
#define vl vector<long long>
typedef long long ll;
using namespace std; vl mul(vl &a,ll b)
{
vl c;
ll lena=a.s;
for(int i=0,t=0;i<lena||t;i++)
{
if(i<lena) t+=a[i]*b;
c.pb(t%10);
t/=10;
}
while(c.s>1&&c.back()==0) c.pop_back();
return c;
} int main()
{
string A;
ll b;
vl a,c;
cin>>A>>b;
ll lena=A.s;
for(int i=lena-1;i>=0;i--) a.pb(A[i]-'0');
c=mul(a,b);
ll lenc=c.s;
for(int i=lenc-1;i>=0;i--) cout<<c[i];
cout<<endl;
return 0;
}

把小数看成整体进行计算,同样注意要去掉前导0.

高精度*高精度

#include<bits/stdc++.h>
#define s size()
#define pb push_back
#define vl vector<long long>
typedef long long ll;
using namespace std; vl mul(vl &a,vl &b)
{
ll lena=a.s;
ll lenb=b.s;
vl c(lena+lenb,0);
for(int i=0;i<lena;i++)
for(int j=0;j<lenb;j++) c[i+j]+=a[i]*b[j];
ll lenc=c.s;
for(int i=0,t=0;i<lenc;i++)
{
t+=c[i];
c[i]=t%10;
t/=10;
}
while(c.s>1&&c.back()==0) c.pop_back();
return c;
} int main()
{
string A,B;
vl a,b,c;
cin>>A>>B;
ll lena=A.s;
ll lenb=B.s;
for(int i=lena-1;i>=0;i--) a.pb(A[i]-'0');
for(int i=lenb-1;i>=0;i--) b.pb(B[i]-'0');
c=mul(a,b);
ll lenc=c.s;
for(int i=lenc-1;i>=0;i--) cout<<c[i];
cout<<endl;
return 0;
}

也是实现手算乘法,用法比较巧妙,建议全文背诵/doge

高精度除法

只贴高精度除低精度,高精度除高精度很麻烦,而且比赛都是会取模的

#include<bits/stdc++.h>
#define s size()
#define pb push_back
#define vl vector<long long>
typedef long long ll;
using namespace std; vl div(vl &a,ll b,ll &r)
{
vl c;
ll lena=a.s;
r=0;
for(int i=lena-1;i>=0;i--)
{
r=r*10+a[i];
c.pb(r/b);
r=r%b;
}
reverse(c.begin(),c.end());
while(c.s>1&&c.back()==0) c.pop_back();
return c;
}
int main()
{
string A;
ll b;
vl a,c;
ll r;
cin>>A>>b;
ll lena=A.s;
for(int i=lena-1;i>=0;i--) a.pb(A[i]-'0');
c=div(a,b,r);
ll lenc=c.s;
for(int i=lenc-1;i>=0;i--) cout<<c[i];
cout<<endl<<r<<endl;
return 0;
}

其中由于除法是从最高位运算的,要使与其他三个互通,函数里面用了reverse函数调换了位置,时间复杂度有点大,但是方便融合

四个高精度完毕


ACM基础板子的更多相关文章

  1. JAVA ACM 基础

    java ACM Java做ACM-ICPC的特点: (1) 在一般比赛中,Java程序会有额外的时间和空间,而实际上经过实验,在执行计算密集任务的时候Java并不比C/C++慢多少,只是IO操作较慢 ...

  2. ACM基础算法入门及题目列表

    对于刚进入大学的计算机类同学来说,算法与程序设计竞赛算是不错的选择,因为我们每天都在解决问题,锻炼着解决问题的能力. 这里以TZOJ题目为例,如果为其他平台题目我会标注出来,同时我的主页也欢迎大家去访 ...

  3. java编程acm基础

    java还是不错的昂! import java.util.*; import java.io.*; public class text{ static int a=100; public static ...

  4. ACM基础(一)

    比较大的数组应尽量声明在main函数外,否则程序可能无法运行. C语言的数组并不是“一等公民”,而是“受歧视”的.例如,数组不能够进行赋值操作: 在程序3-1中,如果声明的是“int a[maxn], ...

  5. C++ ACM基础

    一.C++结构体 #include <iostream> using namespace std; struct Point{ int x; int y; Point(int x=0,in ...

  6. Python3 acm基础输入输出

    案例一:输入字符串分割并转化成多个int数值 a, b= map(int, input().split()) try: while True: a, b= map(int, input().split ...

  7. 【基础数位DP-模板】HDU-2089-不要62

    不要62 Time Limit: / MS (Java/Others) Memory Limit: / K (Java/Others) Total Submission(s): Accepted Su ...

  8. 【题解】【排列组合】【素数】【Leetcode】Unique Paths

    A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...

  9. JSU 2013 Summer Individual Ranking Contest - 5

    JSU 2013 Summer Individual Ranking Contest - 5 密码:本套题选题权归JSU所有,需要密码请联系(http://blog.csdn.net/yew1eb). ...

随机推荐

  1. 仿String()构造器函数 【总结】

    需求 实现以下方法: 控制台结果: 需求分析: 首先确定new调用的this和什么对象绑定,如果跟默认返回的对象绑定肯定做不到 [ ] 这样的访问,所以要在构造器内部返回一个包装过的数组 1.leng ...

  2. Java例题_30 在已经排好序的数组中插入值

    1 /*30 [程序 30 插入数字] 2 题目:有一个已经排好序的数组.现输入一个数,要求按原来的规律将它插入数组中. 3 程序分析:首先判断此数是否大于最后一个数,然后再考虑插入中间的数的情况,插 ...

  3. springboot+druid报错log4j:WARN No appenders could be found for logger (druid.sql.Connection). log4j:WARN Please initialize the log4j system properly.

     解决方案:新建文件log4j.properties log4j.rootLogger=DEBUG, stdout log4j.appender.stdout=org.apache.log4j.Con ...

  4. Spring Boot 轻量替代框架 Solon 1.3.15 发布

    Solon 是一个微型的Java开发框架.项目从2018年启动以来,参考过大量前人作品:历时两年,4000多次的commit:内核保持0.1m的身材,超高的跑分,良好的使用体验.支持:RPC.REST ...

  5. 3w 字长文爆肝 Java 基础面试题!太顶了!!!

    hey guys ,这不是也到了面试季了么,cxuan 又打算重新写一下 Java 相关的面试题,先从基础的开始吧,这些面试题属于基础系列,不包含多线程相关面试题和 JVM 相关面试题,多线程和 JV ...

  6. [高精度]P1096 Hanoi 双塔问题

    Hanoi 双塔问题 题目描述 给定A.B.C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形). 现 ...

  7. 不想eject,还咋修改create-react-app的配置?

    一.先抛问题 许多刚开始接触create-react-app框架的同学,不免都会有个疑问:如何在不执行eject操作的同时,修改create-react-app的配置.今天胡哥就来带大家一起来看看这个 ...

  8. Pyinstaller原理详解

    Pyinstaller原理详解 什么是Pyinstaller Pyinstaller可以把Python程序打包成exe文件,可以在没有Python的电脑上运行,主要用于生产用. Python.h! 在 ...

  9. [Vue warn]: Unknown custom element: <terminal-process> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

    Vue组件注册报错问题 import 不要加{},排查出如果页面引用单个组件的时候不要加上{}中括号,引入多个组件时才能派上用场,中括号去除问题即可解决.

  10. Day13_67_interrupt() 方法

    interrupt() 方法 中断线程 * interrupt()方法的简单理解 - interrupt() 方法只是改变线程的阻塞状态而已,让一个正在阻塞状态的线程,恢复执行.但是它不会中断一个正在 ...