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\n",ans);
82     }
83     
84     return 0;
85 }

 

posted @ 2018-08-01 21:58  wawawa8  阅读(153)  评论(0编辑  收藏  举报