8-25模拟赛解题报告

又爆零了,真开心 (⺻▽⺻)


T1.字符串

题目大意:两个字符串可重集\(S,T\),每次可添加或删除一个字符串,每次操作完后求\(\sum lcp(s_i,t_i)~ ,s_i\in S,t_i\in T\)的最大值。其中\(lcp\)表示字符串最长公共前缀。

又是一道考场想出正解打炸的题。。 (T_T)

这道题其实很简单,用字典树略做处理就好了,几乎可以做模板题了。因为在Trie树上前缀相同的字符串一开始经过的一些字符肯定是相同的,所以我们在添加或者删除操作经过一些节点时,将这个点所对应的集合的\(sum\)值加一就好了,然后\(ans\)要加上两个集合在这个点所对应的\(sum\)更小的那一个就可以了。

小结:

解题关键:想到字符前缀与Trie树的关系

芝士点:Trie树

手起,码落:

#include<bits/stdc++.h>
#define re register
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
const int N=500005,W=2000005;
int rt,cnt=1,n,now=1,pl[N],pr[N],ans;
int mp[W][26],num[W][2],mi[W][26];
char ch[W],opt[1];
bool SorT[N];
inline void add(int l,int val)
{
	re int r=pr[l],ST=SorT[l];l=pl[l],rt=1;
	for(re int i=l,mid;i<=r;i++)
	{
		mid=ch[i]-'a';
		if(mp[rt][mid]) rt=mp[rt][mid];
		else rt=mp[rt][mid]=++cnt;
		ans-=min(num[rt][0],num[rt][1]);
		num[rt][ST]+=val;
		ans+=min(num[rt][0],num[rt][1]);
	}
}
int main()
{
	scanf("%d",&n);
	for(re int i=1,type,x;i<=n;i++)
	{
		scanf("%d",&type);
		if(type==1)
		{
			pl[i]=now;
			scanf("%s%s",opt,ch+now);
			now+=strlen(ch+now),pr[i]=now-1;
			if(opt[0]=='T')SorT[i]=1;
			add(i,1);
		}
		else scanf("%d",&x),add(x,-1);
		printf("%d\n",ans);
	}
	return 0;
}

T2.生成随机数

题目大意:开始\(X=0\),每次\(X\)会有一定概率的加上\(\begin{bmatrix}0,1,2~...~n\end{bmatrix}\)之间的一个数并对\(m\)取模,求\(X\)加到\(K\)的概率次数。

这题考场上真的毫无头绪 (订正的时候也是,就只会打一个\(O(n^3)\)的高斯消元。。

小结:咕咕咕~~


T3.疏散

题目大意:三栋楼之间有两个楼道,有\(n\)个人分布在这三栋楼里,求所有人下楼的最小时间,任意两个人不能在同一位置,且左边一栋楼的人不会从右楼道下,右边也如此。

下午订正一个半小时,想了一个错误算法,真好,直接咕掉。。

错就错吧,错的也讲一下,设\(L_i\)\(R_i\)分别为第\(i\)个人从左楼道和右楼道下去的最小时间。如果第\(i\)个人在左边一栋楼,则\(R_i=inf\)

对于左栋楼,设\(t_i\ge L_i\)且不与他人冲突,为第\(i\)个人下楼的时间。右边也一样处理。然后对于中间楼道,可以二分答案,先找左边楼道不大于二分值的空缺加进去,如果左边满了就加右边,至于有没有空缺,用并查集维护即可。

然后我的并查集就打炸了

小结:

解题关键:想到简化题意,想到冲突的解决办法

芝士点:并查集,二分答案

手起,码~码炸了。。

posted @ 2020-08-27 21:36  Chester1011  阅读(87)  评论(0编辑  收藏  举报
/*simplememory*/