又爆零了,真开心 (⺻▽⺻)
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)个人下楼的时间。右边也一样处理。然后对于中间楼道,可以二分答案,先找左边楼道不大于二分值的空缺加进去,如果左边满了就加右边,至于有没有空缺,用并查集维护即可。
然后我的并查集就打炸了
小结:
解题关键:想到简化题意,想到冲突的解决办法
芝士点:并查集,二分答案
手起,码~码炸了。。