java取模运算定律_年后排序+ST表+ksm+矩阵ksm+斐波那契数列矩阵ksm+归并排序

这篇博客探讨了Java中的模运算定律,并介绍了多种排序算法,包括归并排序、快速排序和堆排序。此外,还详细讲解了矩阵快速幂在解决斐波那契数列问题中的应用,以及如何使用ST表进行区间最大值查询。最后,讨论了矩阵乘法规则和矩阵快速幂的实现,展示了如何通过这些技术优化算法效率。
摘要由CSDN通过智能技术生成

看点

牛逼的斐波那契切矩阵快速幂

排序

STL针对区间的函数

\(sort\)

\(merge_sort\),归并

\(quick_sort\),快速

\(heap_sort\),堆排序

其他

\(reverse (a+1,a+n+1)\) 翻转 \(a+1\)到 \(a+n\)

\(unique (a+1,a+n+1)\) 去重数组,例子:\(11233556667-->1234567...\),前提条件,去重数组必须是有序

//unique有返回值的

//int m=unique(z+1,z+n+1)-z-1,去重得到的数量

z[1]--z[n];

sort(z+1, z+1+n);

int m=unique(z+1,z+1+n)-z-1;

计数排序(桶排序)

\(n<10^6, a[i]<10^6\)

桶: \(cnt[]\)

线性算法:\(O(N+M)\)

int main()

{

scanf("%d", &n);

for (int i=1;i<=n;i++)

{

int v;

scanf("%d",&v);

cnt[v]++;

}

for (int a=0;a<=1000000;a++)

for (int b=1;b<=cnt[a];b++)

printf("%d\n",a);

}

//条件范围只可以小于1000000

//复杂度O(M+N)

归并排序(分治)

核心思想:分

三个目标:左排序,右排序,归并,无限循环

分:dfs

治:两个指针每次比较左右两边最小的数,通过不断的比较,可以将两个有序数组组成一个有序数组

\(O(nlogn)\)

分成 \(logN\) 层

每一层都是 \(O(N)\), 所以 \(O(NlogN)\)

int z[23333];

void merge_sort(int l,int r)//现在对z[1]--z[n]归并排序

{

//分

if (l==r) return;

int mid=(l+r)>>1;

merge_sort(1,mid);

mergr_sort(mid+1,r);

//治

int p1=l, p2=mid+1;//p1代表左边第一个数, p2 代表右边第一个数

for (int a=l;a<=r;a++)

{

if (p1>mid) y[a]=z[p2++];//左边的数都用逛了

else if(p2>r) y[a]=z[p1++];

else if(z[p1]

else y[a]=z[p2++];

}

for (int a=l;a<=r;a++) z[a]=y[a];

}

//O(nlogn)

5e7f142371880dc9a7a5f73d92f5c16f.png

逆序对

条件: \(ia[j]\)

思路:

分:存在三种情况左右中,算出三种情况的数量并合起来

治:排序的过程,计算中的情况

如果治时在去右边去数时,加上最右边x就可以,妙蛙~

#include

#include

#include

#define int long long

using namespace std;

const int B=1e6+10;

int z[B],n,y[B];

int ans;

int merge_sort(int l,int r)

{

if (l==r) return 0;

int mid=(l+r)>>1;

int ans=merge_sort(l,mid)+merge_sort(mid+1,r);

int p1=l,p2=mid+1;

for (int i=l;i<=r;i++)

{

if(p1>mid) y[i]=z[p2++];

else if(p2>r) y[i]=z[p1++];

else if(z[p1]<=z[p2]) y[i]=z[p1++];

else y[i]=z[p2++],ans+=mid-p1+1;

}

for (int i=l;i<=r;i++) z[i]=y[i];

return ans;

}

main()

{

scanf("%lld",&n);

for (int i=1;i<=n;i++) scanf("%lld",&z[i]);

int ans=merge_sort(1,n);

printf("%lld",ans);

}

前缀和思想

Q:"%@%&*&@#^@@!#&&&%&((%&%"

变式 1:

\(a_1\times a_2\times a_3\times a_4..a_n\)

求\(a_l...\times a_r\)

\(\frac{sum[r]}{sum[l]}\)

变式 2:

是否可以用前缀和维护前缀最大值?

\(b_i=max\{a_1,a_2\}\)

无法得到区间最大值

这叫做不满足区间减法性质

那么改如何求

ST表--> (动态规划)

\(f[i][j]\) 从\(a_i\) 开始的 \(2^j\) 个数的最大值

目标

求\(f[i][j]\)

初始化 \(f[i][0]=a_i\)

\(f[i][j] = max\{f[i][j-1],f[i+2^{j-1}][j-1]\}\)

思想:分治

int f[10010][20];

int main()

{

scanf("%d",&n)

for (int i=1;i<=n;i++) cin>>a[i];

//先枚举j在枚举i,先求j-1,在知道j,

for (int i=1;i<=n;i++) f[i][0]=a[i];

// x << y = x*2^y

// x >> y = x/2^y

for (int j=1;(1<

for (int i=1; i + (1<

f[i][j] = max(f[i][j-1],f[i+(1<

}

用\(f[i][j]\) 求最大值

求(2--5)的最大值 \(f[2][2]\)

求(2--6)的最大值

在求\(max\) 中重复数字出现是不影响答案

那么问题二就是,一个长度为 \(5\) 的区间可以盖住两个 \(4\) 区间即 \(max\{f[2][2],f[3][2]\}\)

那么覆盖区间怎么找

#include

#include

#include

using namespace std;

const int B=1e5+10;

int f[B][20], k[B], n, a[B], m;

int main()

{

scanf("%d%d",&n,&m);

for (int i=1;i<=n;i++) scanf("%d",&a[i]);

for (int i=1;i<=n;i++) f[i][0]=a[i];

for (int j=1;j<=21;j++)

for (int i=1;i+(1<

f[i][j]=max(f[i][j-1],f[i+(1<

for (int i=1;i<=m;i++)

{

int l,r;

scanf("%d%d",&l,&r);

int kk=log2(r-l+1);

printf("%d\n",max(f[l][kk],f[r-(1<

}

}

快速幂

\(x^y\%p\)

\(x<10^9\)

举个栗子

求 \(x^{37}= x^{18}\times x=x^{2\times 9}\times x=x^{2\times4\times2}\times x\times x\)

int ksm(int x, int p, int k){

int res = 1;

while(p)

{

if(p&1) res=x*res%k;

x*=x;//不能同时乘和取模

x%=k;

p>>=1;

}

return res%k;

}

矩阵乘法

矩阵大小相同才可进行运算法则

矩阵 \(A(n\times m)\) 和 \(B(m \times k)\) 相乘,要求第一个矩阵的列数必须要等于第二个矩阵的行数,得到矩阵\(C(n\times k)\)

法则

具备结合律 即 \((A\times B)\times C= A\times(B\times C)\)

不具备交换律 即 \(A\times B \ != B \times A\)(因为横和高不同,形成的矩阵也就不同)

左分配律 即 \(A\times(B+C)=A\times B+A\times C\)

右分配律 即 \((A+B) \times C=A\times C + B\times C\)

矩阵的零次幂

任何矩阵的 \(0\) 次幂又称单位矩阵 \(E\), 其定义是他的左上角到右下角的对角线(又称主对角线)为 \(1\), 其余全部为零 \(0\)

法则是:任何矩阵和单位矩阵 \(E\) 相乘都得本身,如图所示

\[\begin{bmatrix}1&\cdots&0\\\vdots&1&\vdots\\0&\cdots&1\end{bmatrix}

\]

模拟过程

\[\begin{bmatrix}1&2\\3&4\end{bmatrix}\times\begin{bmatrix}1&2&3\\4&5&6\end{bmatrix}\

\]

若得到矩阵中\((2,3)\) 的数字则:

\[H\ ofA\ 2_{nd}\ --3,4\\

\times,\times\\

L\ ofB\ 3_{rd}\ --3,3\\

9+12=21

\]

即 \((2,3)\) 数字为 \(21\)

struct matrix

{

int n,m;

int z[10][10];

matrix(){

n=m=0;

memset(z,0,sizeof(z));

}

};

matrix operator *(const matrix &m1, const matrix &m2)

{

matrix m3;

m3.n = m1.n;

m3.m = m2.m;

for (int i=1;i<=m3.n;i++)

for (int j=1;j<=m3.m;j++)

for (int k=1;k<=m1.m; k++)

m3.z[i][j] += m1.z[i][k]*m2.z[k][j];

return m3;

}

int main(){

matrix m1;

m1.n=1,m1.m =2;

m1.z[1][1]=1;m1.z[1][2]=2;

matrix m2;

m2.n=2; m2.m =2;

m2.z[1][1]=1;m2.z[1][2]=1;

m2.z[2][1]=1;m2.z[2][2]=0;

matrix m3=m1*m2;

for (int i=1;i<=m3.n;i++)

{

for (int j=1;j<=m3.m;j++)

cout<

puts("");

}

return 0;

}

矩阵快速幂

int n, k;

struct matrix

{

int z[101][101];

};

matrix operator *(const matrix &m1, const matrix &m2)

{

matrix m3;

for (int i=1;i<=n;i++)

for (int j=1;j<=n;j++)

m3.z[i][j]=0;

for (int i=1;i<=n;i++)

for (int j=1;j<=n;j++)

for (int k=1;k<=n;k++)

{

m3.z[i][j]+=m1.z[i][k]*m2.z[k][j]%mod;

m3.z[i][j]%=mod;

}

return m3;

}

matrix ksm(matrix x,int p)

{

matrix res;

for (int i=1;i<=n;i++) res.z[i][i]=1;

while(p>0){

if(p&1) res=res*x;

x=x*x;

p>>=1;

}

return res;

}

main() {

cin>>n>>k;

matrix m1;

for (int i=1;i<=n;i++)

for (int j=1;j<=n;j++)

{

cin>>m1.z[i][j];

}

matrix m=ksm(m1,k);

for (int i=1;i<=n;i++){

for (int j=1;j<=n;j++)

cout<

puts("");

}

return 0;

}

斐波那契矩阵快速幂(升级版)

首先斐波那契数列的通式是:

\[f[i] = f[i-1]+f[i-2]

\]

我们要求出 \(f[n]\) 就需要枚举,时间复杂度为 \(O(n)\)

若用矩阵乘法和快速幂,就可达到 \(O(logn)\)

原理:\(f[i]\) 受到前两项的影响,那么可以设置一个 \(1\times2\) 的矩阵,原因是若所求受到的影响为 \(n\) 个变量,则可以设置一个 \(1\times n\)的矩阵转移,即:

\[\begin{vmatrix}f[i]&f[i-1]\end{vmatrix}

\]

其次,利用矩阵乘法就要保证 \(f[i]\) 运算后是往后移一位的,与之相乘的一定是一个\(2\times 2\) 的矩阵,怎么找呢?

我们不妨这么设

\[\begin{vmatrix}a&b\\c&d\end{vmatrix}

\]

因为两者相乘后我们得到的答案为

\[\begin{vmatrix}f[i+1]&f[i]\end{vmatrix}

\]

所以可以列出方程式

\[\begin{cases}af[i]+cf[i-1]=f[i+1]\\bf[i]+df[i-1]=f[i]\end{cases}

\]

我们可以有合并同类项可得二式的解为 \(b=1,d=0\)

而一式可以将右侧的 \(f[i+1]\) 拆分成 \(f[i]+f[i-1]\) 再进行合并同类项

得:\(a=1,c=1\)

综上所述,我们的相乘矩阵为:

\[\begin{vmatrix}1&1\\1&0\end{vmatrix}

\]

那么式子就可以推导为

\[\begin{vmatrix}f[i]&f[i-1]\end{vmatrix}\times \begin{matrix}\underbrace{\begin{vmatrix}1&1\\1&0\end{vmatrix}\times\begin{vmatrix}1&1\\1&0\end{vmatrix}.....\times\begin{vmatrix}1&1\\1&0\end{vmatrix}}\\n\end{matrix}=\begin{vmatrix}f[n+1]&f[n]\end{vmatrix}

\]

化简得

\[\begin{vmatrix}f[i]&f[i-1]\end{vmatrix}\times \begin{vmatrix}1&1\\1&0\end{vmatrix}^{n}=\begin{vmatrix}f[n+1]&f[n]\end{vmatrix}

\]

因此我们可以用矩阵快速幂,在 \(O(logn)\) 级别求出

太妙了~

struct matrix

{

int n,m;

int z[10][10];

matrix(){

n=m=0;

memset(z,0,sizeof(z));

}

};

matrix operator*(const matrix &m1, const matrix &m2)

{

matrix m3;

m3.n = m1.n;

m3.m = m2.m;//矩阵原理

for (int i=1;i<=m3.n;i++)

//乘法分配律,乘法交换律,思考?????????????????????????

for (int k=1;k<=m1.m;k++)

for (int j=1;j<=m3.m;j++)

m3.z[i][j] += m1.z[i][k] * m2.z[k][j];

return m3;//矩阵乘法

}

matrix ksm(matrix m, int n)

{

if (n==0){//当n==0时存在一个特殊的矩阵上述会给出

matrix z;

z.n=z.m=m.n;

for (int i=1;i<=z.n;i++)

z.z[i][i]=1;//特殊的快速幂即只有对角线为1,其余全是0

return z;

}

matrix z=ksm(m,n/2);

z=z*z;

if (n%2==1) z=z*m;//利用承载运算符,所以乘的时候直接就是矩阵乘法

return z;

}

int main()

{

scanf("%d",&n);

matrix m1;

m1.n =1;m1.m=2;

m1.z[1][1]=1;m1.z[1][2]=0;

matrix m2;

m2.n=m2.m=2;

m2.z[1][1]=1; m2.z[1][2]=1;

m2.z[2][1]=1; m2.z[2][2]=0;

m1 = m1 * ksm(m2, n);

printf("%d\n"m1.z[1][2]);

}

标签:begin,matrix,int,矩阵,times,vmatrix,ksm,排序

来源: https://www.cnblogs.com/lToZvTe/p/14407671.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值