8-25模拟赛解题报告

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


T1.字符串

题目大意:两个字符串可重集(S,T),每次可添加或删除一个字符串,每次操作完后求(sum lcp(s_i,t_i)~ ,s_iin S,t_iin 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
",ans);
	}
	return 0;
}

T2.生成随机数

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

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

小结:咕咕咕~~


T3.疏散

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

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

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

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

然后我的并查集就打炸了

小结:

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

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

手起,码~码炸了。。

原文地址:https://www.cnblogs.com/jkzcr01-QAQ/p/13574144.html