ACM大一寒假集训1.3

【模板】后缀排序

看这篇学的,觉得讲的挺好后缀数组算法总结

char s[maxn];
int sa[maxn],x[maxn],y[maxn],c[maxn],n;
void build(int m)
{
    int i;
    for(i=0;i<m;i++) c[i]=0;
    for(i=0;i<n;i++) c[x[i]=s[i]]++;
    for(i=1;i<m;i++) c[i] += c[i-1];
    for(i=n-1;i>=0;i--) 
      sa[--c[x[i]]]=i;
	// for (int i=0;i<n;i++) cout<<sa[i]<<endl;
    for(int k=1;k<n;k<<=1) 
    {   //倍增,将k凑成k*2长度,k>=n就没必要了
        int p=0;
        for(i=n-1;i>=n-k;i--) y[p++]=i;
        for(i=0;i<n;i++) 
          if(sa[i]>=k) y[p++]=sa[i]-k;//sa[i]>=k的位置才能做第二关键字
		
        for(i=0;i<m;i++) c[i]=0;
        for(i=0;i<n;i++) c[x[y[i]]]++;
        for(i=1;i<m;i++) c[i]+=c[i-1];
        for(i=n-1;i>=0;i--) 
          sa[--c[x[y[i]]]]=y[i];//两次排序后的数组
		//下标是排名,值为首字母位置:sa,y
		//下标是位置,值是排名:x
        swap(x,y);//y:第一关键字排序   x:上一轮的rank
        p=1;x[sa[0]]=0;
        for(i=1;i<n;i++)
          if(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k])
            x[sa[i]]=p-1;
          else x[sa[i]]=p++;
        if(p>=n) break;
        m=p;  
    }
    return ;
}

int main()
{
    scanf("%s",s);
    n=strlen(s);
    build(10000);
    for (int i=0;i<n;i++)
    cout<<sa[i]+1<<" ";
    return 0;
}

难度:3

T1洛谷P2870 [USACO07DEC]Best Cow Line G

明显的贪心是:比较首字符和尾字符的大小,取小的。

但对于大小相同的就不好判断了,我们用f[i]表示从ii开始的后缀,用g[i]表示从ii开始的前缀。那么遇到str[L]=str[R]时,比较f[L]和g[R]即可,这个可以用后缀数组排序实现。

难度:3

T2P4051 [JSOI2007]字符加密

把字符串首尾相接,扩展为原来的两倍,就能按后缀数组的方法处理

难度:3

矩阵快速幂模板

#include<bits/stdc++.h> 
using namespace std;
long long mod=1000000007,n,k;
struct node
{
	long long m[200][200];
}a;
node x(node a,node b)
{
	node t;
	for (int i=0;i<n;i++)
		for (int j=0;j<n;j++)
		{
			t.m[i][j]=0;
			for (int k=0;k<n;k++)
			t.m[i][j]=(t.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
		}
	return t;
}
node ksm(node a,long long k)
{
	node ret=a,b=a;k--;
	while (k>0)
	{
		if (k%2==1)
		ret=x(b,ret);
		b=x(b,b);
		k=k/2;
	}
	return ret;
}
int main()
{
	scanf("%lld%lld",&n,&k);
	for (int i=0;i<n;i++)
		for (int j=0;j<n;j++)
		scanf("%lld",&a.m[i][j]);
		a=ksm(a,k);
	for (int i=0;i<n;i++)
	{
		for (int j=0;j<n;j++)
		printf("%lld ",a.m[i][j]);
        printf("\n");
	}
	return 0;
}

T3P1962 斐波那契数列

构造矩阵base=image-20210203023715427

初始矩阵ans=image-20210203023802502

Fn为ans*base^(n-2),用矩阵快速幂即可

难度:2

广义斐波那契数列是更一般的形式)

T4矩阵加速(数列)

和上一题差不多,构造个矩阵就行了

难度:2

矩阵经典问题有向图的可达矩阵

例题:HDU2167

难度:3

posted @ 2021-02-03 03:16  蛙蛙1551  阅读(18)  评论(0编辑  收藏  举报