zoukankan      html  css  js  c++  java
  • P3435 [POI2006]OKR-Periods of Words

    P3435 [POI2006]OKR-Periods of Words

    卡了好久,一直不敢确认思路是对的。。。

    这题非常显然可以转化成“对于每一个 (S_{1,cdots,i}) 求出最短公共前后缀 (q_j)”,那么 (ans=sum i-q_i)

    首先求出 (KMP)(next) 数组,那么最短公共前后缀就是在 (next) 不为 (-1) 的情况下不断跳。

    每次暴力跳的复杂度是不对的,实测 TLE 74

    考虑类似并查集的路径压缩进行优化因为中间经过的路径能压缩就压缩,不影响答案(当然也可以连边 (next_i o i) ,跑DAG)

    均摊一下复杂度还是 (O(n))

    另外,教练说字符串下标从零开始是一种信仰,于是我就改了。。。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef double db;
    #define x first
    #define y second
    #define sz(v) (int)v.size()
    #define pb(x) push_back(x)
    #define mkp(x,y) make_pair(x,y)
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
    	while(isdigit(c))x=x*10+c-'0',c=getchar();
    	return f?x:-x;
    }
    #define N 1000005
    int n,P[N];
    char str[N];
    LL ans;
    signed main(){
    	scanf("%d%s",&n,str);
    	int j=-1;P[0]=-1;
    	for(int i=1;i<n;++i){
    		while(~j&&str[j+1]!=str[i])j=P[j];
    		if(str[j+1]==str[i])++j;
    		P[i]=j;
    	}
    	for(int i=0;i<n;++i){
    		j=P[i];
    		while(~j&&~P[j])P[i]=j=P[j];
    		if(~j)ans+=i-j;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    ASP.net 网站项目:Fckeditor使用StepByStep
    SQL2005触发器写法
    Android 中 PopupWindow使用
    storyboard学习笔记-1
    判断两矩形是否相交
    CListCtrl 使用
    字符串和数字之间的转换(Unicode)
    【转】全特化/偏特化
    判断点是否在多边形内——射线法
    c++强制转化
  • 原文地址:https://www.cnblogs.com/zzctommy/p/13889081.html
Copyright © 2011-2022 走看看