zoukankan      html  css  js  c++  java
  • 洛谷P2375 [NOI2014]动物园(KMP+倍增优化)

    题目链接https://www.luogu.com.cn/problem/P2375

    解法:这个其实就是无限把i往net[i]跳,当net[i]小于等于一半后然后计数,直到跳到net[i]==0为止。但是因为时间复杂度的原因需要优化。

    一开始在getchar函数中预处理把num[i]全部算出来,num[i]=num[net[i]]]+1,因为是由i跳到net[i]的。然后可以想到用倍增来记录跳的位置,fa[i][0]=net[i];后面搞的时候直接特判一下就行。

    70分代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,n,a) for(int i=n;i>=a;i--)
    #define endl '
    '
    #define eps 0.000000001
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    #define IO ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
    const int INF=0x3f3f3f3f;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    const int mod=1e9+7;
    const int maxn=1e6+5;
    char p[maxn];int net[maxn];
    int num[maxn],fa[maxn][30],n;
    void getnext(char *p){
        int lenp=strlen(p);
        int k=-1;net[0]=-1;int j=0;
        while(j<lenp){
            if(k==-1||p[j]==p[k]){
                k++,j++;
                net[j]=k;
            }else{
                k=net[k];
            }
            if(net[j]) num[j]=num[net[j]]+1;
            else num[j]=0; 
            fa[j][0]=net[j];
        }
    }
    void bz(){
        for(ll j=1;j<=19;j++){
            for(ll i=1;i<=n;i++){
                fa[i][j]=fa[fa[i][j-1]][j-1];
            }
        }
    }
    int main(){
        int T;cin>>T;
        while(T--){
            scanf("%s",p);
            n=strlen(p);        
            getnext(p);bz();    
            ll ans=1;
            rep(i,1,n){
                int p=i;
                for(int j=19;j>=0;j--){
                    int cur=fa[p][j];
                    if(cur*2>i){
                        p=fa[p][j];
                    }
                }
                ans*=1LL*(num[p]+1);ans%=mod;
            }
            cout<<ans<<endl;
        }
    }
    View Code

    为啥只有70分呢?这就要牵扯到一个内存问题,倍增数组的反复横跳,具体就是计算机内部原理的了

    反复横跳:缓存不命中,要读内存,再不命中,再读内存

     问了群友才算一知半解吧,具体操作其实和之前bz一样,只不过把fa[maxn][30]换成fa[30][maxn]就能快很多

    100分AC代码(手动开O2优化):

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,n,a) for(int i=n;i>=a;i--)
    #define endl '
    '
    #pragma GCC optimize(2)
    #define eps 0.000000001
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    #define IO ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
    const int INF=0x3f3f3f3f;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    const int mod=1e9+7;
    const int maxn=1e6+5;
    char p[maxn];int net[maxn];
    int num[maxn],fa[30][maxn],n;
    void getnext(char *p){
        int lenp=strlen(p);
        int k=-1;net[0]=-1;int j=0;
        while(j<lenp){
            if(k==-1||p[j]==p[k]){
                k++,j++;
                net[j]=k;
            }else{
                k=net[k];
            }
            if(net[j]) num[j]=num[net[j]]+1;
            else num[j]=0; 
            fa[0][j]=net[j];
        }
    }
    void bz(){
        for(ll j=1;j<=19;j++){
            for(ll i=1;i<=n;i++){
                fa[j][i]=fa[j-1][fa[j-1][i]];
            }
        }
    }
    int main(){
        int T;scanf("%d",&T);
        while(T--){
            scanf("%s",p);
            n=strlen(p);        
            getnext(p);bz();    
            ll ans=1;
            rep(i,1,n){
                int p=i;
                for(int j=19;j>=0;j--){
                    int cur=fa[j][p];
                    if(cur>(i/2)){
                        p=fa[j][p];
                    }
                }
                ans*=1LL*(num[p]+1);ans%=mod;
            }
            printf("%lld
    ",ans);
        }
    }
    View Code
  • 相关阅读:
    使用ServiceStackRedis链接Redis简介
    浅谈SQL SERVER中事务的ACID
    Sql Server查询性能优化之走出索引的误区
    Redis命令总结
    TSQL查询进阶—理解SQL Server中的锁
    SQL Server 2005 分区表实践——分区切换
    SQL Server Profiler 模板
    深入浅出SQL Server中的死锁
    不同的单元中的类可以共用同一个命名空间
    从硬盘上装xp手记(2005.8.14 )
  • 原文地址:https://www.cnblogs.com/Anonytt/p/13378235.html
Copyright © 2011-2022 走看看