• UOJ #35 后缀排序 哈希做法


    题面

    http://uoj.ac/problem/35

    题解

    后缀数组当然可以

    这里用哈希做

    首先排序的问题在哪里

    在于比较两个后缀的复杂度是O(length)的

    但是我们可以通过找LCP来优化比较

    我们二分两个串的LCP的长度 然后通过hash值判断是否相同

    这样我们可以在$O(log l)$的时间内算出两个串的LCP长度

    所以排序的复杂度变成$O(n log ^2 n )$

    然后求出连续两个后缀的LCP还是用二分的方法做 复杂度$O(n log n)$

    总的复杂度$O(n log ^2 n)$

    Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 
     5 ll read(){
     6     ll x=0,f=1;char c=getchar();
     7     while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
     8     while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
     9     return x*f;
    10 }
    11 
    12 const int maxn=1000100;
    13 const int mod=1e9+7;
    14 int mu[maxn],pr[maxn],cnt;
    15 bool isp[maxn];
    16 int fib[maxn],g[maxn],G[maxn],invG[maxn];
    17 int fpw[maxn][3];
    18 
    19 inline int ksm(int a,int b){
    20     int ret=1;
    21     for(int i=0;i<=30;i++){
    22         if(b&1) ret=ret*1ll*a%mod;
    23         a=a*1ll*a%mod;
    24         b=b>>1;
    25         if(b==0) return ret;
    26     }
    27 }
    28 
    29 inline int inv(int a){
    30     return ksm(a,mod-2);
    31 }
    32 
    33 int main(){
    34 #ifdef LZT
    35     freopen("in","r",stdin);
    36 #endif
    37     mu[1]=1;
    38     memset(isp,1,sizeof(isp));
    39     for(int i=2;i<=1000000;i++){
    40         if(isp[i]){
    41             pr[++cnt]=i;
    42             mu[i]=-1;
    43         }
    44         for(int j=1;j<=cnt && i*pr[j]<=1000000;j++){
    45             isp[i*pr[j]]=0;
    46             if(i%pr[j]==0) break;
    47             mu[i*pr[j]]=-mu[i];
    48         }
    49     }
    50     
    51     fib[1]=1;
    52     for(int i=2;i<=1000000;i++)
    53         fib[i]=(fib[i-1]+fib[i-2])%mod;
    54     for(int i=1;i<=1000000;i++){
    55         fpw[i][0]=inv(fib[i]);
    56         fpw[i][1]=1;
    57         fpw[i][2]=fib[i];
    58     }
    59     for(int i=1;i<=1000000;i++)
    60         g[i]=1;
    61     for(int i=1;i<=1000000;i++)
    62         for(int j=i;j<=1000000;j+=i)
    63             g[j]=g[j]*1ll*fpw[i][mu[j/i]+1]%mod;
    64     G[0]=1;
    65     for(int i=1;i<=1000000;i++)
    66         G[i]=G[i-1]*1ll*g[i]%mod;
    67     
    68     invG[0]=1;
    69     for(int i=1;i<=1000000;i++)
    70         invG[i]=inv(G[i]);
    71     
    72     int tc=read();
    73     while(tc--){
    74         int n=read(),m=read();
    75         int j;
    76         int ans=1;
    77         for(int i=1;i<=min(n,m);i=j+1){
    78             j=min(n/(n/i),m/(m/i));
    79             ans=ans*1ll*ksm(G[j]*1ll*invG[i-1]%mod,(n/i)*1ll*(m/i)%(mod-1))%mod;
    80         }
    81         printf("%d
    ",ans);
    82     }
    83     
    84     return 0;
    85 }
  • 相关阅读:
    LeetCode Minimum Path Sum
    第六章-2-数组练习
    第六章-1-数组练习
    第五章-for循环的练习
    第四章:if else switch使用
    第三章
    实训篇-JavaScript-打地鼠
    实训篇-Html-注册页面【简单】
    实训篇-Html-计算器
    实训篇-JavaScript-陶渊明去没去过桃花源
  • 原文地址:https://www.cnblogs.com/wawawa8/p/9404183.html
Copyright © 2020-2023  润新知