zoukankan      html  css  js  c++  java
  • CF802I Fake News (hard) (后缀数组+单调栈)

    CF802I Fake News (hard)

    这个题和 CF123D 很像,代码只有一点点不同。

    首先看到子串的问题容易想到后缀数组,所以我们可以先对字符串求一遍后缀数组以及 height 数组。

    接下来怎么做?我们其实可以想得到单调栈。我们可以考虑对于 height 数组维护一个单调递增的栈。一旦我们要弹出栈顶元素时,我们就知道他一定会对答案做出新贡献,即 \(cnt(s,p)>1\)。我们只需要把这些有新贡献的串的个数算出来,然后把其他只出现过一次的串的数量统计出来,答案就算出来了。

    时间复杂度 \(O(n\log n+n)\)

    //Don't act like a loser.
    //This code is written by huayucaiji
    //You can only use the code for studying or finding mistakes
    //Or,you'll be punished by Sakyamuni!!!
    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    
    int read() {
    	char ch=getchar();
    	int f=1,x=0;
    	while(ch<'0'||ch>'9') {
    		if(ch=='-')
    			f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9') {
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	return f*x;
    }
    
    const int MAXN=1e5+10; 
    
    int n,m;
    int sa[MAXN],rnk[MAXN],height[MAXN],tmp[MAXN],a[MAXN],b[MAXN],cnt[MAXN],calc[MAXN];
    char s[MAXN];
    
    void bucket_sort(int v[]) {
    	fill(cnt,cnt+m+1,0);
    	for(int i=1;i<=n;i++) {
    		cnt[v[i]+1]++;
    	}
    	for(int i=1;i<=m;i++) {
    		cnt[i]+=cnt[i-1];
    	}
    	for(int i=1;i<=n;i++) {
    		tmp[++cnt[v[sa[i]]]]=sa[i];
    	}
    	for(int i=1;i<=n;i++) {
    		sa[i]=tmp[i];
    	}
    }
    
    void get_sa() {
    	for(int i=1;i<=n;i++) {
    		rnk[i]=tmp[i]=s[i];
    		sa[i]=i;
    	}
    	sort(tmp+1,tmp+n+1);
    	m=unique(tmp+1,tmp+n+1)-tmp-1;
    	for(int i=1;i<=n;i++) {
    		rnk[i]=lower_bound(tmp+1,tmp+m+1,rnk[i])-tmp;
    	}
    	
    	for(int l=1;l<n;l<<=1) {
    		for(int i=1;i<=n;i++) {
    			a[i]=rnk[i];
    			b[i]=(i+l<=n? rnk[i+l]:0);
    		}
    		bucket_sort(b);
    		bucket_sort(a);
    		
    		m=0;
    		for(int i=1;i<=n;i++) {
    			if(a[sa[i]]!=a[sa[i-1]]||b[sa[i]]!=b[sa[i-1]]) {
    				m++;
    			}
    			rnk[sa[i]]=m;
    		}
    	}
    }
    
    void get_height() {
    	int h=0;
    	for(int i=1;i<=n;i++) {
    		if(h) {
    			h--;
    		}
    		if(rnk[i]==1) {
    			continue;
    		}
    		
    		int p=i+h;
    		int q=sa[rnk[i]-1]+h;
    		
    		while(p<=n&&q<=n&&s[p]==s[q]) {
    			p++;
    			q++;
    			h++;
    		}
    		height[rnk[i]]=h;
    	}
    }
    
    int solve() {
    	int ans=n*(n+1)/2;
    	stack<int> stk;
    	for(int i=2;i<=n+1;i++) {
    		while(!stk.empty()&&height[stk.top()]>height[i]) {
    			int y=height[stk.top()];
    			int x=height[i];
    			stk.pop();
    			int z=(stk.empty()? 0:height[stk.top()]);
    			int len=i-(stk.empty()? 1:stk.top());
    			ans+=(y-max(x,z))*(len*len-len);
    		}
    		stk.push(i);
    	}
    	return ans;
    }
    
    signed main() {
    	int t=read();
    	
    	while(t--) {
    		scanf("%s",s+1);
    		n=strlen(s+1);
    		
    		get_sa();
    		get_height();
    		
    		printf("%lld\n",solve());
    	} 
    	return 0;
    }
    
    

    对于单调栈的思考,我有一个小技巧,可以通过画柱形图来帮助思考,这样会很直观

  • 相关阅读:
    【转】基于 Apache 在本地配置多个虚拟主机
    ubuntu linux下各种格式软件包的安装卸载
    钩子
    静态方法中不能使用 $this
    Redis Sentinel机制与用法说明【转】
    CI 分页类的使用
    MySQL压力测试
    简单配置.htaccess就可以实现的10个功能
    bzoj 3529 数表
    poj2773 Happy 2006
  • 原文地址:https://www.cnblogs.com/huayucaiji/p/CF802I.html
Copyright © 2011-2022 走看看