九下四月中旬日记

4.11

闲话

  • 白天考试,依次是英语早读,理综,英语,数学,长达 \(2h\) 的文综自习,文综。
    • 理综
      • 物理
        • 多选 \(BD\) 涂成了 \(CD\) ,挂了 \(3pts\)
        • 因不知道水是比热容最大的液体,多分讨了一种情况,挂了 \(1pts\)
      • 化学
        • 物质 看出了 溶质 ,挂了 \(2pts\)
    • 英语
      • \(D\) 篇阅读感觉挺贴合自身实际的。
    • 数学
      • 已知 \(\frac{x+3}{(x-2)^{2}}=\frac{A}{(x-2)^{2}}+\frac{B}{(x-2)}\) ,求 \(A-B\)
        • 正解:假设 \(A,B\) 为常数,然后就做完了。
        • 非正解:不可做,跳了。
      • 关于 不透明的桌子 上放着一个 不透明的立方体 (为什么不是骰子) , 能看到的所有面 ,但没有交代从哪个方向看。
      • 只能用 普及模拟1 的一句话来形容整张卷子。
    • 文综自习
      • 课代表要求自由背诵,但前排靠门处在背诵,后排在聊天,被年级主任抓了,然后 \(D\) 了一顿。
    • 文综
      • 写完卷后 \(50min\) 都在罚坐,翻了翻世界古代史。
  • 晚上现班主任因我们太浮躁,还有被年级主任抓了的事情,把我们 \(D\) 了一顿。为了更好地营造反思环境,他甚至关了灯 \(D\) 我们。

做题纪要

4.12

闲话

  • 白天讲评试卷,但体育课正常上。
  • 物理课,物理老师讲了下今年强基的情况,劝诫我们不要偏科。
  • 历史课前,历史老师统计了下班级总分排名情况和历史满分情况。信奥作为前两百最少的( \(3/33\) ),历史满分却是最多的 (\(6/11\)) 。
  • 化学老师请假了,请了化学奥赛教练来代课,讲完后不知道讲啥就讲了讲今年强基的情况和他当时在 HZ 的 \(whk\) 成绩,劝诫我们不要偏科。
  • 因白天讲评占了奥赛课,所以第 \(9\) 节课到晚三都改奥赛。

做题纪要

luogu P7409 SvT

  • 多倍经验: CF1073G Yet Another LCP Problem

  • 记给出的后缀去重后得到 \(a\) ,将其按 \(rk\) 排序后,由 1.字符串专题 B CF1073G Yet Another LCP Problem\(\sum\limits_{i=1}^{|a|}\sum\limits_{j=i+1}^{|a|}LCP(s_{a_{i} \sim n},s_{a_{j} \sim n})=\sum\limits_{i=1}^{k}\sum\limits_{j=i}^{k}\min\limits_{h=i}^{j}\{ g_{h} \}\)

    点击查看代码
    const ll p=23333333333333333;
    ll sa[500010],rk[1000010],oldrk[1000010],id[500010],cnt[500010],key[500010],height[500010],a[3000010],fminn[500010][20],g[3000010];
    __int128_t f[3000010];
    char s[500010];
    void write(__int128_t x)
    {
    	if(x<0)
    	{
    		putchar('-');
    		x=-x;
    	}
    	if(x>9)
    	{
    		write(x/10);
    	}
    	putchar((x%10)+'0');
    }
    bool cmp(ll a,ll b)
    {
    	return rk[a]<rk[b];
    }
    ll val(char x)
    {
    	return (ll)x;
    }
    void counting_sort(ll n,ll m)
    {
    	memset(cnt,0,sizeof(cnt));
    	for(ll i=1;i<=n;i++)
    	{
    		cnt[key[i]]++;
    	}
    	for(ll i=1;i<=m;i++)
    	{
    		cnt[i]+=cnt[i-1];
    	}
    	for(ll i=n;i>=1;i--)
    	{
    		sa[cnt[key[i]]]=id[i];
    		cnt[key[i]]--;
    	}
    }
    void init_sa(char s[],ll len)
    {
    	ll m=127,tot=0,num=0,i,j,w;
    	for(i=1;i<=len;i++)
    	{
    		rk[i]=val(s[i]);
    		id[i]=i;
    		key[i]=rk[id[i]];
    	}
    	counting_sort(len,m);
    	for(w=1;tot!=len;w<<=1,m=tot)
    	{
    		num=0;
    		for(i=len;i>=len-w+1;i--)
    		{
    			num++;
    			id[num]=i;
    		}
    		for(i=1;i<=len;i++)
    		{
    			if(sa[i]>w)
    			{
    				num++;
    				id[num]=sa[i]-w;
    			}
    		}
    		for(i=1;i<=len;i++)
    		{
    			key[i]=rk[id[i]];
    		}
    		counting_sort(len,m);
    		for(i=1;i<=len;i++)
    		{
    			oldrk[i]=rk[i];
    		}
    		tot=0;
    		for(i=1;i<=len;i++)
    		{
    			tot+=(oldrk[sa[i]]!=oldrk[sa[i-1]]||oldrk[sa[i]+w]!=oldrk[sa[i-1]+w]);
    			rk[sa[i]]=tot;
    		}
    	}
    	for(i=1,j=0;i<=len;i++)
    	{
    		j-=(j>=1);
    		while(s[i+j]==s[sa[rk[i]-1]+j])
    		{
    			j++;
    		}
    		height[rk[i]]=j;
    	}
    }
    void init(ll n,ll a[])
    {
    	memset(fminn,0x3f,sizeof(fminn));
    	for(ll i=1;i<=n;i++)
    	{
    		fminn[i][0]=a[i];
    	}
    	for(ll j=1;j<=log2(n);j++)
    	{
    		for(ll i=1;i<=n-(1<<j)+1;i++)
    		{
    			fminn[i][j]=min(fminn[i][j-1],fminn[i+(1<<(j-1))][j-1]);
    		}
    	}
    }
    ll query(ll l,ll r)
    {
    	ll t=log2(r-l+1);
    	return min(fminn[l][t],fminn[r-(1<<t)+1][t]);
    }
    __int128_t ask(ll n,ll k,ll a[])
    {
    	__int128_t sum=0;
    	ll i;
    	stack<ll>st;
    	sort(a+1,a+1+k,cmp);
    	for(i=1;i<=k;i++)
    	{
    		g[i]=query(rk[a[i-1]]+1,rk[a[i]]);
    	}
    	for(i=1;i<=k;i++)
    	{
    		while(st.empty()==0&&g[st.top()]>=g[i])
    		{
    			st.pop();
    		}
    		if(st.empty()==0)
    		{
    			f[i]=(f[st.top()]+g[i]*(i-st.top())%p)%p;
    		}
    		else
    		{
    			f[i]=(f[0]+g[i]*(i-0)%p)%p;
    		}
    		st.push(i);
    		sum=(sum+f[i])%p;
    	}
    	return sum;
    }
    int main()
    {
    	ll n,m,k,i,j;
    	cin>>n>>m>>(s+1);
    	init_sa(s,n);
    	init(n,height);
    	for(j=1;j<=m;j++)
    	{
    		cin>>k;
    		for(i=1;i<=k;i++)
    		{
    			cin>>a[i];
    		}
    		sort(a+1,a+1+k);
    		k=unique(a+1,a+1+k)-(a+1);
    		write(ask(n,k,a));
    		cout<<endl;
    	}
    	return 0;
    }
    

牛客挑战赛74 B 伐木机不要石头!!!(easy version)

  • 排完序后二分维护即可,貌似也可以双指针维护。

  • 不是很理解为什么暴力能跑过去,可能是我复杂度分析假了(?)。

    点击查看暴力代码
    int a[100010],b[100010],vis[100010];
    int main()
    {
    	int n,m,ans=0,pos,l,r,i;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	for(i=1;i<=m;i++)
    	{
    		cin>>b[i];
    	}
    	sort(a+1,a+1+n);
    	sort(b+1,b+1+m);
    	for(i=1;i<=n;i++)
    	{
    		pos=lower_bound(b+1,b+1+m,a[i])-b;
    		if(pos!=m+1)
    		{
    			while(vis[pos]==1)
    			{
    				pos++;
    			}
    			if(pos<=m)
    			{
    				vis[pos]=1;
    				ans++;
    			}
    		}
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    
    点击查看正解代码
    int a[100010],b[100010],vis[100010];
    int main()
    {
    	int n,m,ans=0,pos=0,l,r,i;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	for(i=1;i<=m;i++)
    	{
    		cin>>b[i];
    	}
    	sort(a+1,a+1+n);
    	sort(b+1,b+1+m);
    	for(i=1;i<=n;i++)
    	{
    		pos=lower_bound(b+pos+1,b+1+m,a[i])-b;
    		if(pos!=m+1)
    		{
    			while(vis[pos]==1)
    			{
    				pos++;
    			}
    			if(pos<=m)
    			{
    				vis[pos]=1;
    				ans++;
    			}
    			if(pos==m)
    			{
    				break;
    			}
    		}
    		else
    		{
    			break;
    		}
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

4.13

闲话

  • 历史课,被历史老师 \(D\) 了,调侃我们退步是因为“学奥赛时间很紧张,没时间学 \(whk\) ” 。
  • \(miaomiao\) 叫去开期中总结大会。整了个班级挑战,以前是让学生上去,这次是让班主任上去。现班主任原定是前两百 \(30\) 人,德育主任不同意,遂改成前一百 \(30\) 人,全员前两百。

做题纪要

牛客挑战赛74 A 硫酸钡之梦

  • 赛时把 \(|拿走数量-没拿走数量| \le 1\) 理解成了 \(拿走数量-没拿走数量 \le 1\) ,写了个 \(O(n^{2})\)\(DP\) ,然后就写假了。

  • 为满足 \(|拿走数量-没拿走数量| \le 1\) 的限制,每相邻两个糖果必须选一个。

    点击查看正解代码
    ll a[100010];
    int main()
    {
    	ll n,ans=0,i;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	for(i=1;i<=n;i+=2)
    	{
    		ans+=max(a[i],a[i+1]);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

BZOJ3230 相似子串

  • 对于前缀,将其反过来即可处理。

  • luogu P2408 不同子串个数 ,可以前缀和处理出 \(1 \sim i\) 中共有多少个本质不同的子串,即 \(sum_{i}=sum_{i-1}+n-sa_{i}+1-height_{i}\)

  • 设第 \(x,y\) 名的子串所在的原串的后缀的排名分别为 \(pos_{x},pos_{y}\) ,则其长度分别为 \(len_{x}=height_{pos_{x}}+x-sum_{pos_{x}-1},len_{y}=height_{pos_{y}}+y-sum_{pos_{y}-1}\) ;其所在的反串的后缀的排名分别为 \(pos_{x}'=rk_{n-(sa_{pos_{x}}+len_{x}-1)+1},pos_{y}'=rk_{n-(sa_{pos_{y}}+len_{y}-1)+1}\)

  • 最终,有 \(\begin{cases} a=\min(\min\limits_{i=pos_{x}'+1}^{pos_{y}'} \{ height_{i} \},len_{x},len_{y}) \\ b=\min(\min\limits_{i=pos_{x}+1}^{pos_{y}} \{ height_{i} \},len_{x},len_{y}) \end{cases}\) 即为所求。

    点击查看代码
    ll sa[2][100010],rk[2][200010],oldrk[200010],id[100010],cnt[100010],key[100010],height[2][100010],sum[2][100010],fminn[2][100010][25];
    char s1[100010],s2[100010];
    void init(ll n,ll a[],ll pd)
    {
    	memset(fminn[pd],0x3f,sizeof(fminn[pd]));
    	for(ll i=1;i<=n;i++)
    	{
    		fminn[pd][i][0]=a[i];
    	}
    	for(ll j=1;j<=log2(n);j++)
    	{
    		for(ll i=1;i<=n-(1<<j)+1;i++)
    		{
    			fminn[pd][i][j]=min(fminn[pd][i][j-1],fminn[pd][i+(1<<(j-1))][j-1]);
    		}
    	}
    }
    ll query(ll l,ll r,ll pd)
    {
    	if(l>r)
    	{
    		return 0x3f3f3f3f;
    	}
    	else
    	{
    		ll t=log2(r-l+1);
    		return min(fminn[pd][l][t],fminn[pd][r-(1<<t)+1][t]);
    	}
    }
    ll val(char x)
    {
    	return (ll)x;
    }
    void counting_sort(ll n,ll m,ll sa[])
    {
    	memset(cnt,0,sizeof(cnt));
    	for(ll i=1;i<=n;i++)
    	{
    		cnt[key[i]]++;
    	}
    	for(ll i=1;i<=m;i++)
    	{
    		cnt[i]+=cnt[i-1];
    	}
    	for(ll i=n;i>=1;i--)
    	{
    		sa[cnt[key[i]]]=id[i];
    		cnt[key[i]]--;
    	}
    }
    void init_sa(char s[],ll len,ll pd)
    {
    	ll m=127,tot=0,num=0,i,j,w;
    	for(i=1;i<=len;i++)
    	{
    		rk[pd][i]=val(s[i]);
    		id[i]=i;
    		key[i]=rk[pd][id[i]];
    	}
    	counting_sort(len,m,sa[pd]);
    	for(w=1;tot!=len;w<<=1,m=tot)
    	{
    		num=0;
    		for(i=len;i>=len-w+1;i--)
    		{
    			num++;
    			id[num]=i;
    		}
    		for(i=1;i<=len;i++)
    		{
    			if(sa[pd][i]>w)
    			{
    				num++;
    				id[num]=sa[pd][i]-w;
    			}
    		}
    		for(i=1;i<=len;i++)
    		{
    			key[i]=rk[pd][id[i]];
    		}
    		counting_sort(len,m,sa[pd]);
    		for(i=1;i<=len;i++)
    		{
    			oldrk[i]=rk[pd][i];
    		}
    		tot=0;
    		for(i=1;i<=len;i++)
    		{
    			tot+=(oldrk[sa[pd][i]]!=oldrk[sa[pd][i-1]]||oldrk[sa[pd][i]+w]!=oldrk[sa[pd][i-1]+w]);
    			rk[pd][sa[pd][i]]=tot;
    		}
    	}
    	for(i=1,j=0;i<=len;i++)
    	{
    		j-=(j>=1);
    		while(s[i+j]==s[sa[pd][rk[pd][i]-1]+j])
    		{
    			j++;
    		}
    		height[pd][rk[pd][i]]=j;
    	}
    	for(i=1;i<=len;i++)
    	{
    		sum[pd][i]=sum[pd][i-1]+len-sa[pd][i]+1-height[pd][i];
    	}
    }
    int main()
    {
    	ll n,m,x,y,posx,posy,lenx,leny,a,b,i;
    	cin>>n>>m>>(s1+1);
    	for(i=1;i<=n;i++)
    	{
    		s2[i]=s1[n-i+1];
    	}
    	init_sa(s1,n,0);
    	init(n,height[0],0);
    	init_sa(s2,n,1);
    	init(n,height[1],1);
    	for(i=1;i<=m;i++)
    	{
    		cin>>x>>y;
    		posx=lower_bound(sum[0]+1,sum[0]+1+n,x)-sum[0];
    		posy=lower_bound(sum[0]+1,sum[0]+1+n,y)-sum[0];  
    		if(posx==n+1||posy==n+1)
    		{   
    			cout<<"-1"<<endl;
    		}
    		else
    		{
    			lenx=height[0][posx]+x-sum[0][posx-1];
    			leny=height[0][posy]+y-sum[0][posy-1];
    			b=min(query(posx+1,posy,0),min(lenx,leny));
    			posx=rk[1][n-(sa[0][posx]+lenx-1)+1];
    			posy=rk[1][n-(sa[0][posy]+leny-1)+1];
    			if(posx>posy)
    			{
    				swap(posx,posy);
    			}
    			a=min(query(posx+1,posy,1),min(lenx,leny));
    			cout<<a*a+b*b<<endl;
    		}
    	}   
    	return 0;
    }
    

4.14

闲话

  • 体活的时候来机房后 \(feifei\) 称下午的比赛起床后再来打,“让他们一个小时也没关系”。
  • 下午打北交大的比赛 2024.4.14 【数据删除】(密码看摘要)\(feifei\) 因此还把网关了,离谱。
  • 晚上开班会,分析了下成绩,喂了不少鸡汤。

做题纪要

bjtuOJ 2055. 公园这天下大雨

bjtuOJ 2065. 小黄人闹翻天

bjtuOJ 2005. Magic Math

bjtuOJ 2059. Linux模拟器 - 2

bjtuOJ 2058. 助手酱的理论计算

4.15

闲话

  • 不知道 \(HE\) 体育“专家” 是怎么想到让足球在篮球场测试的,草地秒变水泥地。
  • 昨天的题比赛里面看不了,还搬到了 bjtuOJ ,但在学校上不去,而且 \(huge\)\(miaomiao\) 也没搬到学校 OJ 上。

做题纪要

luogu P2870 [USACO07DEC] Best Cow Line G

  • 多倍经验: luogu P6140 [USACO07NOV] Best Cow Line S

  • 设当前队首、尾分别为 \(l,r\) 。当 \(s_{l} \ne s_{r}\) 时,取较小的那一个即可;当 \(s_{l}=s_{r}\) 时,类似依次判断 \(s_{l+i}\)\(s_{r-i}\) 即可,等价于比较 \(s_{l}s_{l+1}s_{l+2} \dots s_{r}\)\(s_{r}s_{r-1}s_{r-2} \dots s_{l}\) 之间的大小关系,可以用后缀数组优化判断。

    • 原理
      • 对于 \(s_{a \sim b}\)\(s_{c \sim d}\) ,若 \(LCP(s_{a \sim |s|},s_{c \sim |s|}) \ge \min(|s_{a \sim b}|,|s_{c \sim d}|)\) ,则 \(s_{a \sim b}<s_{c \sim d} \iff |s_{a \sim b}|<|s_{c \sim d}|\) ;否则 \(s_{a \sim b}<s_{c \sim d} \iff rk_{a}<rk_{c}\)
    点击查看代码
    int sa[1000010],rk[2000010],oldrk[2000010],id[1000010],cnt[1000010],key[1000010];
    char s[1000010];
    int val(char x)
    {
    	return (int)x;
    }
    void counting_sort(int n,int m)
    {
    	memset(cnt,0,sizeof(cnt));
    	for(int i=1;i<=n;i++)
    	{
    		cnt[key[i]]++;
    	}
    	for(int i=1;i<=m;i++)
    	{
    		cnt[i]+=cnt[i-1];
    	}
    	for(int i=n;i>=1;i--)
    	{
    		sa[cnt[key[i]]]=id[i];
    		cnt[key[i]]--;
    	}
    }
    void init_sa(char s[],int len)
    {
    	int m=127,tot=0,num=0,i,w;
    	for(i=1;i<=len;i++)
    	{
    		rk[i]=val(s[i]);
    		id[i]=i;
    		key[i]=rk[id[i]];
    	}
    	counting_sort(len,m);
    	for(w=1;tot!=len;w<<=1,m=tot)
    	{
    		num=0;
    		for(i=len;i>=len-w+1;i--)
    		{
    			num++;
    			id[num]=i;
    		}
    		for(i=1;i<=len;i++)
    		{
    			if(sa[i]>w)
    			{
    				num++;
    				id[num]=sa[i]-w;
    			}
    		}
    		for(i=1;i<=len;i++)
    		{
    			key[i]=rk[id[i]];
    		}
    		counting_sort(len,m);
    		for(i=1;i<=len;i++)
    		{
    			oldrk[i]=rk[i];
    		}
    		tot=0;
    		for(i=1;i<=len;i++)
    		{
    			tot+=(oldrk[sa[i]]!=oldrk[sa[i-1]]||oldrk[sa[i]+w]!=oldrk[sa[i-1]+w]);
    			rk[sa[i]]=tot;
    		}
    	}
    }
    int main()
    {
    	int n,len,sum=0,l=1,r,i;
    	cin>>n;
    	r=len=n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>s[i];
    	}
    	for(i=1;i<=n;i++)
    	{
    		s[i+n+1]=s[n-i+1];
    	}
    	s[n+1]='#';
    	len=2*n+1;
    	init_sa(s,len);   
    	while(l<=r)
    	{
    		if(s[l]<s[r])
    		{
    			cout<<s[l];
    			l++;
    		}
    		else
    		{
    			if(s[l]>s[r])
    			{
    				cout<<s[r];
    				r--;
    			}
    			else
    			{   
    				if(rk[l]<rk[n+(n-r+1)+1])
    				{
    					cout<<s[l];
    					l++;
    				}
    				else
    				{
    					cout<<s[r];
    					r--;
    				}
    			}
    		}
    		sum++;
    		if(sum%80==0)
    		{
    			cout<<endl;
    		}
    	}
    	return 0;
    }
    

4.16

闲话

  • \(miaomiao\) 觉得题做得差不多了(人均 \(3.6/9\) 道题),说明天要讲字符串的题。
  • 小班会上现班主任称 @wkh2008@xrlong@K8He@jijidawang 四人停课去搞奥赛怎么保证每时每刻在学奥赛,而且去机房时能以百米冲刺的速度跑去机房,但为什么中午不能留到 \(12:20\) ,还说找时间要找他们谈谈。

做题纪要

luogu P2178 [NOI2015] 品酒大会

  • 由于 \(r\) 相似同时也是 \(r'(0 \le r'<r)\) 相似,考虑从 \(n-1 \sim 0\) 依次处理,便于更新答案,方案数做后缀和即可,最大值取后缀最大值即可。

  • \(r\) 相似等价于 \(LCP(s_{p \sim n},s_{q \sim n}) \ge r\) ,此时可以转化为将后缀数组划分为若干个连续 \(LCP\) 长度大于等于某一值的段,即将 \(height\) 划分为若干个连续最小值大于等于某一值的段病统计划分的段的答案。

  • \(r\) 递减时,满足条件的区间个数总是越来越少,且新区间都是由两个或两个以上的原区间相连所得。故可以从大到小考虑所有 \(height\) ,每次将 \(sa_{i-1}\)\(sa_{i}\) 进行合并,更新答案。

  • 由于 \(a\) 中有负数,故需要分别记录集合中的最大值、最小值。

    点击查看代码
    ll sa[300010],rk[600010],oldrk[600010],id[300010],cnt[300010],key[300010],height[300010],maxx[300010],minn[300010],p[300010],f[300010],siz[300010],mul_max[300010],sum[300010],ans[300010];
    char s[300010];
    ll val(char x)
    {
        return (ll)x;
    }
    void counting_sort(ll n,ll m)
    {
        memset(cnt,0,sizeof(cnt));
        for(ll i=1;i<=n;i++)
        {
            cnt[key[i]]++;
        }
        for(ll i=1;i<=m;i++)
        {
            cnt[i]+=cnt[i-1];
        }
        for(ll i=n;i>=1;i--)
        {
            sa[cnt[key[i]]]=id[i];
            cnt[key[i]]--;
        }
    }
    void init_sa(char s[],int len)
    {
        ll m=127,tot=0,num=0,i,j,w;
        for(i=1;i<=len;i++)
        {
            rk[i]=val(s[i]);
            id[i]=i;
            key[i]=rk[id[i]];
        }
        counting_sort(len,m);
        for(w=1;tot!=len;w<<=1,m=tot)
        {
            num=0;
            for(i=len;i>=len-w+1;i--)
            {
                num++;
                id[num]=i;
            }
            for(i=1;i<=len;i++)
            {
                if(sa[i]>w)
                {
                    num++;
                    id[num]=sa[i]-w;
                }
            }
            for(i=1;i<=len;i++)
            {
                key[i]=rk[id[i]];
            }
            counting_sort(len,m);
            for(i=1;i<=len;i++)
            {
                oldrk[i]=rk[i];
            }
            tot=0;
            for(i=1;i<=len;i++)
            {
                tot+=(oldrk[sa[i]]!=oldrk[sa[i-1]]||oldrk[sa[i]+w]!=oldrk[sa[i-1]+w]);
                rk[sa[i]]=tot;
            }
        }
        for(i=1,j=0;i<=len;i++)
        {
            j-=(j>=1);
            while(s[i+j]==s[sa[rk[i]-1]+j])
            {
                j++;
            }
            height[rk[i]]=j;
        }
    }
    ll find(ll x)
    {
        return (f[x]==x)?x:f[x]=find(f[x]);
    }
    void merge(ll x,ll y,ll h)
    {
        x=find(x);
        y=find(y);
        if(x!=y)
        {
            mul_max[x]=max(mul_max[x],max(mul_max[y],max(maxx[x]*maxx[y],max(maxx[x]*minn[y],max(minn[x]*maxx[y],minn[x]*minn[y])))));
            sum[h]+=siz[x]*siz[y];
            ans[h]=max(ans[h],mul_max[x]);
            minn[x]=min(minn[x],minn[y]);
            maxx[x]=max(maxx[x],maxx[y]);
            f[y]=x;
            siz[x]+=siz[y];
        }
    }
    bool cmp(int a,int b)
    {
        return height[a]>height[b];
    }
    int main()  
    {
        ll n,i;
        cin>>n>>(s+1);
        memset(mul_max,-0x3f,sizeof(mul_max));
        memset(ans,-0x3f,sizeof(ans));
        for(i=1;i<=n;i++)
        {
            cin>>maxx[i];
            minn[i]=maxx[i];
            p[i]=f[i]=i;
            siz[i]=1;
        }
        init_sa(s,n);
        sort(p+1,p+1+n,cmp);
        for(i=1;i<=n;i++)
        {
            merge(sa[p[i]],sa[p[i]-1],height[p[i]]);
        }
        for(i=n-1;i>=0;i--)
        {
            sum[i]+=sum[i+1];
            ans[i]=max(ans[i],ans[i+1]);
        }
        for(i=0;i<=n-1;i++)
        {
            cout<<sum[i]<<" "<<(sum[i]!=0)*ans[i]<<endl;
        }
        return 0;
    }
    

bjtuOJ 2064. Dream

bjtuOJ 2062. cats与数组替换

4.17

闲话

  • 去上体育课的路上看见中考招生会的牌子在博艺馆旁边,但上面没有 HZ ,原因人尽皆知。

做题纪要

bjtuOJ 2061. 小太阳

bjtuOJ 2063. 区间旋转排序

4.18

闲话

做题纪要

UVA10870 Recurrences

  • \(F_{n}=\begin{bmatrix} f_{n} & f_{n+1} & f_{n+2} & \dots & f_{n+d-1} \end{bmatrix}\) ,容易有 \(\begin{aligned} F_{n} &=\begin{bmatrix} f_{n} & f_{n+1} & f_{n+2} & \dots & f_{n+d-1} \end{bmatrix} \\ &=\begin{bmatrix} f_{n-1} & f_{n} & f_{n+1} & \dots & f_{n+d-2} \end{bmatrix} \times \begin{bmatrix} 0 & 0 & 0 & \dots & a_{d} \\ 1 & 0 & 0 & \dots & a_{d-1} \\ 0 & 1 & 0 & \dots & a_{d-2} \\ \dots & \dots & \dots & \dots & \dots & \\ 0 & 0 & 0 & \dots & a_{1} \end{bmatrix} \\ &=\begin{bmatrix} f_{n-2} & f_{n-1} & f_{n} & \dots & f_{n+d-3} \end{bmatrix} \times \begin{bmatrix} 0 & 0 & 0 & \dots & a_{d} \\ 1 & 0 & 0 & \dots & a_{d-1} \\ 0 & 1 & 0 & \dots & a_{d-2} \\ \dots & \dots & \dots & \dots & \dots & \\ 0 & 0 & 0 & \dots & a_{1} \end{bmatrix}^{2} \\ &=\begin{bmatrix} f_{n-3} & f_{n-2} & f_{n-1} & \dots & f_{n+d-4} \end{bmatrix} \times \begin{bmatrix} 0 & 0 & 0 & \dots & a_{d} \\ 1 & 0 & 0 & \dots & a_{d-1} \\ 0 & 1 & 0 & \dots & a_{d-2} \\ \dots & \dots & \dots & \dots & \dots & \\ 0 & 0 & 0 & \dots & a_{1} \end{bmatrix}^{3} \\ &= \dots \\ &=\begin{bmatrix} f_{1} & f_{2} & f_{3} & \dots & f_{d} \end{bmatrix} \times \begin{bmatrix} 0 & 0 & 0 & \dots & a_{d} \\ 1 & 0 & 0 & \dots & a_{d-1} \\ 0 & 1 & 0 & \dots & a_{d-2} \\ \dots & \dots & \dots & \dots & \dots & \\ 0 & 0 & 0 & \dots & a_{1} \end{bmatrix}^{n-1} \\ &=F_{1} \times \begin{bmatrix} 0 & 0 & 0 & \dots & a_{d} \\ 1 & 0 & 0 & \dots & a_{d-1} \\ 0 & 1 & 0 & \dots & a_{d-2} \\ \dots & \dots & \dots & \dots & \dots & \\ 0 & 0 & 0 & \dots & a_{1} \end{bmatrix}^{n-1} \end{aligned}\)

    点击查看代码
    struct Matrix
    {
    	ll ma[20][20];
    	Matrix()
    	{
    		memset(ma,0,sizeof(ma));
    	}
    }f,a;
    Matrix mul(Matrix a,Matrix b,ll n,ll m,ll k,ll p)
    {
    	Matrix c;
    	for(ll i=1;i<=n;i++)
    	{
    		for(ll j=1;j<=k;j++)
    		{
    			for(ll h=1;h<=m;h++)
    			{
    				c.ma[i][j]=(c.ma[i][j]+(a.ma[i][h]%p)*(b.ma[h][j]%p)%p)%p;
    			}
    		}
    	}
    	return c;
    }
    Matrix qpow(Matrix a,ll b,ll p,ll n)
    {
    	Matrix ans;
    	for(ll i=1;i<=n;i++)
    	{
    		ans.ma[i][i]=1;
    	}
    	while(b>0)
    	{
    		if(b&1)
    		{
    			ans=mul(ans,a,n,n,n,p);
    		}
    		b>>=1;
    		a=mul(a,a,n,n,n,p);
    	}
    	return ans;
    }
    int main()
    {
    	ll n,m,b,k,p,i,j;
    	while(cin>>m>>b>>p)
    	{
    		if(m==0&&b==0&&p==0)
    		{
    			break;
    		}
    		else
    		{
    			n=1;
    			k=m;
    			b--;
    			for(i=1;i<=m;i++)
    			{
    				for(j=1;j<=m;j++)
    				{
    					a.ma[i][j]=0;
    				}
    			}
    			for(i=m;i>=1;i--)
    			{
    				cin>>a.ma[i][m];
    			}
    			for(i=1;i<=m;i++)
    			{
    				cin>>f.ma[1][i];
    			}
    			for(i=1;i<=m-1;i++)
    			{
    				a.ma[i+1][i]=1;
    			}
    			cout<<mul(f,qpow(a,b,p,m),n,m,k,p).ma[1][1]<<endl;
    		}
    	}
    	return 0;
    }
    

UVA1362 Exploring Pyramids

  • \(f_{l,r}\) 表示 \([l,r]\) 对应的二叉树的个数,状态转移方程为 \(f_{l,r}=\begin{cases} 1 & l=r \\ [s_{l}=s_{r}] \times \sum\limits_{i=l+2}^{r}[s_{l}=s_{i}] \times f_{l+1,i-1} \times f_{i,r} & l \ne r\end{cases}\)

    点击查看代码
    const ll p=1000000000;
    ll f[400][400];
    char s[400];
    int main()
    {
    	ll n,len,l,r,i;
    	while(cin>>(s+1))
    	{
    		n=strlen(s+1);
    		memset(f,0,sizeof(f));
    		for(i=1;i<=n;i++)
    		{
    			f[i][i]=1;
    		}
    		for(len=1;len<=n;len++)
    		{
    			for(l=1,r=l+len-1;r<=n;l++,r++)
    			{
    				if(s[l]==s[r])
    				{
    					for(i=l+2;i<=r;i++)
    					{
    						f[l][r]=(f[l][r]+(s[l]==s[i])*f[l+1][i-1]*f[i][r]%p)%p;
    					}
    				}
    			}
    		}
    		cout<<f[1][n]<<endl;
    	}
    	return 0;
    }
    

4.19

闲话

  • 早上现班主任又 \(D\)\(D\) @wkh2008@xrlong@K8He@jijidawang ,称他们整天都在学奥赛,效率不会太高;假期校内集训是推进度的,校外集训是增长见识的;喂了喂鸡汤。

做题纪要

CF1535F String Distance

4.20

闲话

  • 早上因右厕所水管炸了给吵醒了。
  • \(miaomiao\) 问了问 1.字符串专题 的题做得怎么样了,然后说给高一讲概率期望的时候,让我们和他们一起听课。
  • 体活又被现班主任叫回去了,说体育没满分的体活建议去练体育,年级部帮处理好场地和器材了。
  • 去操场的路上,看见不少高中的在打羽毛球、乒乓球、篮球,感到挺震惊,可能是之前没去过的原因。顺便买了本数学选修三的必刷题。
  • 晚上有 \(ABC\) ,找 \(miaomiao\) 请假说要我们和现班主任说好,但我们没找到现班主任。
  • 晚上考理综,卷子貌似是县城里出的卷子,有点水,一节课两张卷没压力。
  • 因这周不放假,所以考完理综后年级部安排放《感动中国》的视频。但体活的时候忘了找现班主任请假了,找 \(miaomiao\) 请假没有成功,称其挺有意义的,建议我们看看。

做题纪要

SP3267 DQUERY - D-query

  • 强化版: luogu P1972 [SDOI2009] HH的项链

  • 不带修莫队板子。

    • 将询问离线后排序,然后顺序处理每一个询问,暴力从上一个区间的答案转移到下一个区间答案。
      • 普通排序方式为以 \(l\) 所在的块的编号为第一关键字,以 \(r\) 为第二关键字升序排序。
      • 奇偶化排序即对于属于奇数块的询问,将 \(r\) 升序排序,对于属于偶数块的询问,将 \(r\) 降序排序。当指针 \(r\) 处理完这个奇数块的问题时,在向左移动的途中处理偶数块的问题,再向右移动的途中处理下一个奇数块的问题,以此来优化指针 \(r\) 的移动次数。
    • 块长取 \(\frac{n}{\sqrt{m}}\)
    点击查看代码
    int a[1000010],cnt[1000010],ans[1000010],L[1000010],R[1000010],pos[1000010],klen,ksum;
    struct ask
    {
    	int l,r,id;
    }q[1000010];
    bool q_cmp(ask a,ask b)
    {
    	return (pos[a.l]==pos[b.l])?((pos[a.l]%2==1)?(a.r<b.r):(a.r>b.r)):(a.l<b.l);//奇偶化排序
    }
    void init(int n,int m)
    {
    	klen=n/sqrt(m)+1;//防止出现 n<sqrt(m) 的情况
    	ksum=n/klen;
    	for(int i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}	
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(int i=1;i<=ksum;i++)
    	{
    		for(int j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    		}
    	}
    }
    void add(int x,int &sum)
    {
    	cnt[a[x]]++;
    	sum+=(cnt[a[x]]==1);
    }
    void del(int x,int &sum)
    {
    	cnt[a[x]]--;
    	sum-=(cnt[a[x]]==0);
    }
    int main()
    {
    	int n,m,l=1,r=0,sum=0,i;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	cin>>m;
    	init(n,m);
    	for(i=1;i<=m;i++)
    	{
    		cin>>q[i].l>>q[i].r;
    		q[i].id=i;
    	}
    	sort(q+1,q+1+m,q_cmp);
    	for(i=1;i<=m;i++)
    	{
    		while(l>q[i].l)//循环位置不建议更改	
    		{
    			l--;//保留该点贡献
    			add(l,sum);
    		}
    		while(r<q[i].r)
    		{
    			r++;//保留该点贡献
    			add(r,sum);
    		}
    		while(l<q[i].l)
    		{
    			del(l,sum);
    			l++;//删去该点贡献
    		}
    		while(r>q[i].r)
    		{
    			del(r,sum);
    			r--;//删去该点贡献
    		}
    		ans[q[i].id]=sum;
    	}
    	for(i=1;i<=m;i++)
    	{
    		cout<<ans[i]<<endl;
    	}
    	return 0;
    }
    

luogu P3901 数列找不同

  • \(a_{l},a_{l+1},a_{l+2}, \dots ,a_{r}\) 互不相同等价于 \([l,r]\) 内不同数字的数量等于区间长度。

    点击查看代码
    int a[100010],cnt[100010],ans[100010],L[100010],R[100010],pos[100010],klen,ksum;
    struct ask
    {
    	int l,r,id;
    }q[100010];
    bool q_cmp(ask a,ask b)
    {
    	return (pos[a.l]==pos[b.l])?((pos[a.l]%2==1)?(a.r<b.r):(a.r>b.r)):(a.l<b.l);
    }
    void init(int n,int m)
    {
    	klen=n/sqrt(m)+1;
    	ksum=n/klen;
    	for(int i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(int i=1;i<=ksum;i++)
    	{
    		for(int j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    		}
    	}
    }
    void add(int x,int &sum)
    {
    	cnt[a[x]]++;
    	sum+=(cnt[a[x]]==1);
    }
    void del(int x,int &sum)
    {
    	cnt[a[x]]--;
    	sum-=(cnt[a[x]]==0);
    }
    int main()
    {
    	int n,m,l=1,r=0,sum=0,i;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	init(n,m);
    	for(i=1;i<=m;i++)
    	{
    		cin>>q[i].l>>q[i].r;
    		q[i].id=i;
    	}
    	sort(q+1,q+1+m,q_cmp);
    	for(i=1;i<=m;i++)
    	{
    		while(l>q[i].l)
    		{
    			l--;
    			add(l,sum);
    		}
    		while(r<q[i].r)
    		{
    			r++;
    			add(r,sum);
    		}
    		while(l<q[i].l)
    		{
    			del(l,sum);
    			l++;
    		}
    		while(r>q[i].r)
    		{
    			del(r,sum);
    			r--;
    		}
    		ans[q[i].id]=(sum==q[i].r-q[i].l+1);
    	}
    	for(i=1;i<=m;i++)
    	{
    		if(ans[i]==1)
    		{
    			cout<<"Yes"<<endl;
    		}
    		else
    		{
    			cout<<"No"<<endl;
    		}
    	}
    	return 0;
    }
    

luogu P2709 小B的询问

  • 莫队处理即可。

    点击查看代码
    int a[50010],cnt[50010],ans[50010],L[50010],R[50010],pos[50010],klen,ksum;
    struct ask
    {
    	int l,r,id;
    }q[50010];
    bool q_cmp(ask a,ask b)
    {
    	return (pos[a.l]==pos[b.l])?((pos[a.l]%2==1)?(a.r<b.r):(a.r>b.r)):(a.l<b.l);
    }
    void init(int n,int m)
    {
    	klen=n/sqrt(m)+1;
    	ksum=n/klen;
    	for(int i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(int i=1;i<=ksum;i++)
    	{
    		for(int j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    		}
    	}
    }
    void add(int x,int &sum)
    {
    	sum-=cnt[a[x]]*cnt[a[x]];
    	cnt[a[x]]++;
    	sum+=cnt[a[x]]*cnt[a[x]];
    }
    void del(int x,int &sum)
    {
    	sum-=cnt[a[x]]*cnt[a[x]];
    	cnt[a[x]]--;
    	sum+=cnt[a[x]]*cnt[a[x]];
    }
    int main()
    {
    	int n,m,k,l=1,r=0,sum=0,i;
    	cin>>n>>m>>k;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	init(n,m);
    	for(i=1;i<=m;i++)
    	{
    		cin>>q[i].l>>q[i].r;
    		q[i].id=i;
    	}
    	sort(q+1,q+1+m,q_cmp);
    	for(i=1;i<=m;i++)
    	{
    		while(l>q[i].l)
    		{
    			l--;
    			add(l,sum);
    		}
    		while(r<q[i].r)
    		{
    			r++;
    			add(r,sum);
    		}
    		while(l<q[i].l)
    		{
    			del(l,sum);
    			l++;
    		}
    		while(r>q[i].r)
    		{
    			del(r,sum);
    			r--;
    		}
    		ans[q[i].id]=sum;
    	}
    	for(i=1;i<=m;i++)
    	{
    		cout<<ans[i]<<endl;
    	}
    	return 0;	
    }
    

luogu P4462 [CQOI2018] 异或序列

  • 多倍经验: CF617E XOR and Favorite Number

  • 处理出 \(sum_{i}=\bigoplus\limits_{j=1}^{i}a_{j}\) 。由异或性质,有 \(\bigoplus\limits_{i=x}^{y}a_{i}=sum_{x-1} \bigoplus sum_{y}=k\)

  • 此时有 \(\begin{aligned} \sum\limits_{x=l}^{r}\sum\limits_{y=x}^{r}[\bigoplus\limits_{i=x}^{y}a_{i}=k] &=\sum\limits_{x=l}^{r}\sum\limits_{y=x}^{r}[sum_{x-1} \bigoplus sum_{y}=k] \\ &=\sum\limits_{x=l}^{r}\sum\limits_{y=x}^{r}[sum_{x-1} \bigoplus k=sum_{y}] \\ &=\sum\limits_{x=l-1}^{r}\sum\limits_{y=x}^{r}[sum_{x} \bigoplus k=sum_{y}] \end{aligned}\) ,和统计出现次数一个做法。

  • 注意修改时由于 \(\bigoplus k\) 而导致的更新顺序。

    点击查看 hack 数据
    input:
    3 2 0
    0 0 0
    1 2
    3 3
    
    ans:
    3
    1
    
    
    点击查看代码
    ll a[300010],cnt[300010],ans[300010],L[300010],R[300010],pos[300010],klen,ksum;
    struct ask
    {
    	ll l,r,id;
    }q[300010];
    bool q_cmp(ask a,ask b)
    {
    	return (pos[a.l]==pos[b.l])?((pos[a.l]%2==1)?(a.r<b.r):(a.r>b.r)):(a.l<b.l);
    }
    void init(ll n,ll m)
    {
    	klen=n/sqrt(m)+1;
    	ksum=n/klen;
    	for(ll i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;
    		R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;
    		R[ksum]=n;
    	}
    	for(ll i=1;i<=ksum;i++)
    	{
    		for(ll j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;
    		}
    	}
    }
    void add(ll x,ll &sum,ll k)
    {
    	sum+=cnt[a[x]^k];
    	cnt[a[x]]++;
    }
    void del(ll x,ll &sum,ll k)
    {
    	cnt[a[x]]--;
    	sum-=cnt[a[x]^k];
    }
    int main()
    {
    	ll n,m,k,l=1,r=0,sum=0,i;
    	cin>>n>>m>>k;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    		a[i]^=a[i-1];
    	}
    	init(n,m);
    	for(i=1;i<=m;i++)
    	{
    		cin>>q[i].l>>q[i].r;
    		q[i].l--;
    		q[i].id=i;
    	}
    	sort(q+1,q+1+m,q_cmp);
    	for(i=1;i<=m;i++)
    	{
    		while(l>q[i].l)
    		{
    			l--;
    			add(l,sum,k);
    		}
    		while(r<q[i].r)
    		{
    			r++;
    			add(r,sum,k);
    		}
    		while(l<q[i].l)
    		{
    			del(l,sum,k);
    			l++;
    		}
    		while(r>q[i].r)
    		{
    			del(r,sum,k);
    			r--;
    		}
    		ans[q[i].id]=sum;
    	}
    	for(i=1;i<=m;i++)
    	{
    		cout<<ans[i]<<endl;
    	}
    	return 0;
    }
    
posted @ 2024-04-12 21:39  hzoi_Shadow  阅读(67)  评论(1编辑  收藏  举报
扩大
缩小