首页 > 其他分享 >P4384 [八省联考 2018] 制胡窜

P4384 [八省联考 2018] 制胡窜

时间:2022-10-06 15:45:05浏览次数:33  
标签:八省 ch int sum len times 制胡窜 put 联考

P4384 [八省联考 2018] 制胡窜

考虑先将问题转化为切断两个位置使得没有任何一段中包含 \(t\)。则最终的答案为 \(\dbinom{n}{2}-\text{ans}\)。

计 \(t\) 按左端点排序后所有出现的段为 \([l_1,r_1],[l_2,r_2],\dots,[l_k,r_k]\)。

  • 若有三个及三个以上不相交的段,答案为 \(0\)。

  • 若开头段与结尾段相交,即 \(l_k \le r_1\)。

    • 若第一次断在 \([1,l_1)\),则第二次必须断在 \((l_k,r_1]\),共有 \((l_1-1)\times (r_1-l_k)\) 种满足条件的情况。
    • 若第一次断在 \([l_i,l_{i+1})(i+1 \le k)\),第二次必须断在 \((l_k,r_{i+1}]\),即 \(\sum_{i=1}^{k-1} (l_{i+1}-l_i)\times (r_{i+1}-l_k)\)。
    • 若第一次断在 \([l_k,r_1)\),第二次可以断在右面的任意一个位置,则贡献为 \((n-l_k)+(n-(l_k+1))+...+(n-(r1-1))=\frac{(n+n-l_k-r_1-1)\times (r_1-l_k)}{2}\)。
    • 若第一次断在 \([r_1,n]\),第二次断在哪里 \([l_1,r_1]\) 都已经在 \(s\) 中出现,无解。
  • 若开头段与结尾段不相交,即 \(l_k > r_1\)。容易发现第一次一定断在 \([1,r_1)\),第二次一定断在 \((r_1,n]\)。找到最大的 \(i\) 满足 \(r_i \le r_1- \text{len}_t +1\),记为 \(p\)。

    • 若第一次断在 \([1,l_{p})\),第二次断在哪里右边都会多出来一个无法切断的段,无解。

    • 若第一次断在 \([l_p,r_1)\),找到最大的 \(i\) 使得 \(l_i \le r_1\),将其记为 \(q\)。

      • 若第一次断在 \([l_i,l_{i+1})(p \le i< q)\),第二次必须断在 \((l_k,r_{i+1}]\),此时贡献为 \(\sum_{i=p}^{q-1} (l_{i+1}-l_i)\times (r_{i+1}-l_k)\)。
      • 若第一次断在 \([l_q,r_1)\),第二次必须断在 \((l_k,r_{q+1}]\),贡献为 \((r_1-l_q)\times (r_{q+1}-l_k)\)。
    • 若第一次断在 \([r_1,n]\),前面的部分一定会包含 \(t\),无解。

将情况 \(2\) 中带有求和号的式子化简,容易得到

\[\begin{aligned} \sum_{i=1}^{k-1}(l_{i+1}-l_i)\times (r_{i+1}-l_k)&=\sum_{i=1}^{k-1}(r_{i+1}-r_i)\times (r_{i+1}-l_k)\\ &=\sum_{i=1}^{k-1} (r_{i+1}^2-r_i\times r_{i+1}-l_{k}\times r_{i+1}+l_k\times r_i)\\ &=\sum_{i=1}^{k-1} r_{i+1}^2-\sum_{i=1}^{k-1} r_i\times r_{i+1}-(r_k-r_1)\times l_k \end{aligned} \]

可以得到情况 \(3\) 中的式子为

\[\sum_{i=p}^{q-1} r_{i+1}^2-\sum_{i=p}^{q-1} r_i\times r_{i+1}-(r_q-r_p)\times l_k \]

#include<bits/stdc++.h>
using namespace std;
namespace IO{
	template<typename T>inline bool read(T &x){
		x=0;
		char ch=getchar();
		bool flag=0,ret=0;
		while(ch<'0'||ch>'9') flag=flag||(ch=='-'),ch=getchar();
		while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(),ret=1;
		x=flag?-x:x;
        return ret;
	}
	template<typename T,typename ...Args>inline bool read(T& a,Args& ...args){
	    return read(a)&&read(args...);
	}
	template<typename T>void prt(T x){
		if(x>9) prt(x/10);
		putchar(x%10+'0');
	}
	template<typename T>inline void put(T x){
		if(x<0) putchar('-'),x=-x;
		prt(x);
	}
	template<typename T>inline void put(char ch,T x){
		if(x<0) putchar('-'),x=-x;
		prt(x);
		putchar(ch);
	}
	template<typename T,typename ...Args>inline void put(T a,Args ...args){
	    put(a);
		put(args...);
	}
	template<typename T,typename ...Args>inline void put(const char ch,T a,Args ...args){
	    put(ch,a);
		put(ch,args...);
	}
	inline void put(string s){
		for(int i=0,sz=s.length();i<sz;i++) putchar(s[i]);
	}
	inline void put(const char* s){
		for(int i=0,sz=strlen(s);i<sz;i++) putchar(s[i]);
	}
}
using namespace IO;
#define N 200005
#define int long long
#define inf 0x3f3f3f3f
#define ll long long
struct data{
	ll maxn,minn,sum1,sum2;
	data(){maxn=sum1=sum2=0,minn=inf;}
	data(ll _maxn,ll _minn,ll _sum1,ll _sum2){
		maxn=_maxn,minn=_minn,sum1=_sum1,sum2=_sum2;
	}
	inline data operator+(const data &b)const{
		data res=data();
		res.maxn=max(maxn,b.maxn);
		res.minn=min(minn,b.minn);
		res.sum1=sum1+b.sum1;
		res.sum2=sum2+b.sum2+(ll)maxn*(b.minn<inf?b.minn:0);
		return res;
	}
};
struct Segment{
	int idx;
	Segment():idx(0){}
	struct node{
		int ls,rs;
		data val;
	}t[N<<5];
	#define lc(x) t[x].ls
	#define rc(x) t[x].rs
	inline void push_up(int x){
		t[x].val=t[lc(x)].val+t[rc(x)].val;
	}
	inline void update(int &x,int l,int r,int pos){
		if(!x) x=++idx;
		if(l==r) return t[x].val=data(l,l,(ll)l*l,0),void();
		int mid=l+r>>1;
		if(pos<=mid) update(lc(x),l,mid,pos);
		else update(rc(x),mid+1,r,pos);
		push_up(x);
	}
	inline int merge(int x,int y,int l,int r){
		if(!x||!y) return x|y;
		int z=++idx;
		if(l==r){
			t[z].val=data(l,l,(ll)l*l,0);
			return z;
		}
		int mid=l+r>>1;
		lc(z)=merge(lc(x),lc(y),l,mid);
		rc(z)=merge(rc(x),rc(y),mid+1,r);
		push_up(z);
		return z;		
	}
	inline data query(int x,int l,int r,int ql,int qr){
		if(!x||qr<l||ql>r||ql>qr) return data();
		if(ql<=l&&qr>=r) return t[x].val;
		int mid=l+r>>1;
		return query(lc(x),l,mid,ql,qr)+query(rc(x),mid+1,r,ql,qr);
	}
	#undef lc
	#undef rc
}T;
int rt[N],n,m;
struct SAM{
	int idx,lst,pos[N],f[N][23];
	SAM():idx(1),lst(1){} 
	struct node{
		int fa,len,ch[10];
	}t[N];
	inline void extend(int c){
		int p=lst,np=lst=++idx;
		t[np].len=t[p].len+1;
		for(;p&&!t[p].ch[c];p=t[p].fa) t[p].ch[c]=np;
		if(!p) t[np].fa=1;
		else{
			int q=t[p].ch[c];
			if(t[p].len+1==t[q].len) t[np].fa=q;
			else{
				int nq=++idx;
				t[nq]=t[q],t[nq].len=t[p].len+1;
				t[np].fa=t[q].fa=nq;
				for(;p&&t[p].ch[c]==q;p=t[p].fa) t[p].ch[c]=nq;
			}
		}
	}
	inline void insert(char *s){
		for(int i=1;i<=n;i++){
			extend(s[i]-'0');
			pos[i]=lst;
			T.update(rt[lst],1,n,i);
		}
	}
	int id[N],c[N];
	inline void topo_sort(){
		for(int i=1;i<=idx;i++) c[t[i].len]++;
		for(int i=1;i<=n;i++) c[i]+=c[i-1];
		for(int i=1;i<=idx;i++) id[c[t[i].len]--]=i;
		for(int i=1;i<=idx;i++) f[i][0]=t[i].fa;
		for(int j=1;j<=20;j++)
			for(int i=1;i<=idx;i++)
				f[i][j]=f[f[i][j-1]][j-1];
		for(int i=idx;i;i--){
			int x=id[i],f=t[id[i]].fa;
			rt[f]=T.merge(rt[f],rt[x],1,n);
		}
	}
	inline int jump(int x,int k){
		for(int i=20;~i;i--)
			if(t[f[x][i]].len>=k) x=f[x][i];
		return x;
	}
	inline int query(int L,int R){
		int p=pos[R],len=R-L+1;
		p=jump(p,len);
		data now=T.query(rt[p],1,n,1,n);
		ll r1=now.minn,l1=r1-len+1,rk=now.maxn,lk=rk-len+1;
		ll ans=(ll)(n-1)*(n-2)/2;
		if(lk<=r1){
			ans-=(l1-1)*(r1-lk);
			ans-=(r1-lk)*(n+n-lk-r1-1)/2;
			ans-=now.sum1-r1*r1-now.sum2-(rk-r1)*lk;
			return ans;
		}
		data nowp=T.query(rt[p],1,n,1,rk-len);
		ll lp=nowp.maxn-len+1,rp=nowp.maxn;
		if(r1+len<=rp) return ans;
		data nowq=T.query(rt[p],1,n,rp,r1+len-1);
		int lq=nowq.maxn-len+1,rq=nowq.maxn;
		data nowq1=T.query(rt[p],1,n,rq+1,n);
		int rq1=nowq1.minn;
		ans-=(nowq.sum1-rp*rp)-nowq.sum2-(rq-rp)*lk;
		ans-=(r1-lq)*(rq1-lk);
		return ans;
	}
}S;
char s[N];
signed main(){
	read(n,m);
	scanf("%s",s+1);
	S.insert(s);
	S.topo_sort();
	for(int i=1,l,r;i<=m;i++)
		read(l,r),put('\n',S.query(l,r));
	return 0;
}

标签:八省,ch,int,sum,len,times,制胡窜,put,联考
From: https://www.cnblogs.com/fzj2007/p/16757739.html

相关文章

  • [挑战记录][省选联考 2022] 预处理器
    2022100220:30开始答题20:35先水\(20\)分21:30假了,重构2022100306:34\(60\)分19:45继续重构,学习了一些\(\operatorname{string}\)的科技20:18过了#inclu......
  • 22 暑期 CD 班联考 Day4 之降低力度
    WZY在线捐献瞳孔沙城之巅城市定向SUNZH在线学猫叫新知之神SSHWY在线送温暖......
  • 题解【P7515 [省选联考 2021 A 卷] 矩阵游戏】
    P7515[省选联考2021A卷]矩阵游戏解题报告。不一定更好的阅读体验。一年前我在省选赛场上折戟沉沙,一年后我从到下的地方再摔一跤。我成功了,我仍然是以前的那个......
  • 省选联考2022
    省选联考2022先挖个坑,以后再来补(upt2022.9.22:补了d1t2和d2t2。预处理器小模拟,开\(2\)个\(\text{map}\),一个记录定义的变换,一个记录在本次变换中是否已经经过。......
  • CSP-S模拟2(联考)
    差点又双叒叕模拟退役上来先\(\%T2\),然后感觉就差一点,最后搞出来就十点多了..然后心态一度爆炸,有点小摆烂,上厕所冷静一下觉得还有时间,能抢救一下然后开了\(T1\),没......
  • CSP-S模拟2(联考) 谜之阶乘 子集 混凝土粉末 排水系统
    rank4040多分?T1:暴力;T2:构造T2:构造出(1--n)的连续整数分成k组,每组的数加起来一样。(n<=1e6)只要能实现一种构造方案,使得3k个连续数字分k组可以达到(a+b+c)相同(或2k,很显然......
  • P4363 [九省联考 2018] 一双木棋 题解
    一道状压dp题,我写的记忆化搜索。注意到这道题已经下子的区域和未下子的区域有一条轮廓线分割,因此考虑右上到左下记纵向为1,横向为0,状压一下,然后顺着记忆化搜索(有点类似......
  • P6622 [省选联考 2020 A/B 卷] 信号传递
    给定的长度为\(n\)的信号传递序列\(S\),有传递规则:共\(n-1\)次信号传递,第\(i\)次信号传递将把信号从\(S_i\)号信号站传递给\(S_{i+1}\)号。若\(S_{i+1}\)......
  • luogu P8293 [省选联考 2022] 序列变换
    题面传送门因为WC2022考了这种构造,所以下意识将括号序列建树。手玩一下发现第一个操作实际上是干了这个事情:也就是说把用其中一个括号将另一个同层括号在树上移到了下......