2023.3.6~2023.3.7 日寄

2023.3.6 外培 Day 0 日寄

\(~~~~\) 这天主打的就是一个摆。

\(~~~~\) 上午上车前在看《基督山伯爵》,上了车本性暴露直接拿出电脑开摆。先解了半个多小时baba is you,然后打了把以撒,接下来重头戏ser来了于是就全是ser了。

\(~~~~\) 车上最重要的事就是打了个三级袭击,场面大概是两岸猿声啼不住,以及下图是死亡坐标点:

\(~~~~\) 五彩斑斓的世界了属于是。

\(~~~~\) 然后下午到了酒店出去吃了个饭(说实话到外地没吃特色菜感觉有点???来点热干面也不是不行),然后对这顿中式快餐的评价是:不如乡村基。

\(~~~~\) 晚上回去继续摆ser,然后 Rainybunny 这边炸脖龙解放末地,crashed 这边搞了个(半)自动农场,我这边造了个刷怪塔来支持杂七杂八东西的消耗,造完时间不早了没做效率测试。

2023.3.7 外培 Day 1 日寄

模拟赛

递归函数

题意

\(~~~~\) 定义 \(F(n,m)\),当 \(n=0\)\(F(n,m)=1\),当 \(m=0\)\(F(n,m)=n\),否则 \(F(n,m)=F(n-1,m)\times F(n,m-1)\).求 \(F(n,m)\)\(b\) 进制下末尾 \(0\) 的个数对质数 \(998444353\) 取模。
\(~~~~\) \(1\leq n\leq 10^9,1\leq m\leq 16,1\leq b\leq 10\).

题解

\(~~~~\) 怎么办呢,坐牢了呢。

\(~~~~\) 注意到答案也就是求最后的结果可以表示成多少个 \(b\) 的积,当然当 \(b\) 为素数时直接看这个素数的指数,否则看 \(b\) 的最大质因子(针对 \(6,10\))。而当某个质因子指数不为 \(1\) 的时候(针对 \(4,8,9\)) 那发现最后答案是这个除以指数取下整,那为了实现取下整维护结果 \(\bmod~k\times 998444353\) 即可。\(k\) 显然小于等于 \(3\) ,所以可以存。

\(~~~~\) 那么枚举 \(i,j\) 得到 \(p^i\times j\) ,其中 \(p\) 为最大的质因子,我们发现只有 \(F(p^i\times j,0)\) 会产生这个数,所以我们就是求有多少个 \(F(p^i\times j,0)\) 会被计算,显然这是一个在两维上走路的问题,注意到最后一步必须是 \(F(p^i\times j,1) \rightarrow F(p^i\times j,0)\) ,所以是 \(\binom{n-p^i\times j+m-1}{m-1}\) ,不过很显然这个东西不能快速计算。

\(~~~~\) 考虑组合数的递推:\(\binom{n}{m}=\binom{n-1}{m-1}+\binom{n-1}{m}\) 这是一个线性递推,而且我们是存的下的,所以我们考虑用矩阵快速幂算出每个倍数结果。而指数就直接枚举即可。

代码
查看代码
#include <bits/stdc++.h>
#define ll long long
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
ll n,m,b,Ans,MOD=998444353;
struct Matrix
{
	ll a[20][20];
	Matrix(){memset(a,0,sizeof(a));}
}E,Trans,lst;
Matrix operator*(const Matrix &A,const Matrix &B)
{
	Matrix res;
	for(ll i=0;i<=m;i++)
		for(ll j=0;j<=m;j++)
			for(ll k=0;k<=m;k++)
				res.a[i][k]=(res.a[i][k]+A.a[i][j]*B.a[j][k])%MOD; 
	return res;
}
void Solve()
{
	for(ll i=0;i<=m;i++) E.a[i][i]=1;
	Trans.a[0][0]=1;
	for(ll i=1;i<=m;i++)
		for(ll j=i;j<=m;j++) Trans.a[i][j]=1;
	Matrix mul=Trans,add=E;
	add.a[0][1]=1;
	for(ll p=n;p>0;p/=b)
	{
		Matrix Tmp=Trans;
		for(ll i=1;i<b;i++) Trans=Trans*Tmp;
		Matrix Base=Trans*add,res=E;
		ll s=p/b;
		while(s)
		{
			if(s&1) res=res*Base;
			Base=Base*Base,s>>=1;
		}
		for(ll i=0;i<p%b;i++) mul=mul*Tmp;
		res=res*mul;
		Ans=(Ans+res.a[0][m])%MOD;
	}
}
int main() {
	freopen("function.in","r",stdin);
	freopen("function.out","w",stdout);
	read(n);read(m);read(b);ll Div=1;
	if(b==6) b=3;
	if(b==10) b=5;
	if(b==4) b=2,MOD*=2,Div=2;
	if(b==9) b=3,MOD*=2,Div=2;
	if(b==8) b=2,MOD*=3,Div=3;
	Solve();
	printf("%lld",Ans/Div);
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。
*/

火力规划 / 「CF575I」 Robots protection

题意

\(~~~~\) \(q\) 次询问,每次覆盖一个点某四分之一个曼哈顿距离圆,或者查询一个点被多少四分之一圆覆盖。保证被覆盖的区域横纵坐标都在 \([1,n]\) 之中。
\(~~~~\) \(1\leq n\leq 1000,1\leq q\leq 10^5\).

题解

\(~~~~\) 这题评分只有 \(\text{2800}\) /jk

\(~~~~\) 首先注意到通过坐标变换,四种四分之一曼哈顿圆都可以看做一种来处理,我们就只考虑向左下的那一个。

\(~~~~\) 如图,紫红色的那个就是需要覆盖的区域,那么我们可以看做黄色和紫红色整个减去两个紫红色部分的值。

\(~~~~\) 两个部分的并是一个一维区间和问题,那直接用BIT维护即可。

\(~~~~\) 重点在于两个部分的值,我们发现我们可以把黄色部分看做平行四边形。(如果在方框里“看起来”不是你也可以把他拓展成平行四边形,因为四周反正不影响)具体来说记平行四边形内点的坐标 \((x',y')\) 那我们一定有 \(x'+y'\in [x+y-r,x+y]\),并且两个部分分别为 \(x'<x\)\(y'<y\)

\(~~~~\) 那么两个部分分别有两个维上的限制,那用两个二维BIT维护即可。

代码
查看代码
#include <bits/stdc++.h>
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
struct node{
	int op,dir,x,y,r;
}Q[100005];
int n,q;
struct BIT{
	int tr[2][5005][10005];	
	inline int lowbit(int x){return x&(-x);}
	void Add(int x,int Y,int op,int val)
	{
		for(;x<=n;x+=lowbit(x))
			for(int y=Y;y<=2*n;y+=lowbit(y)) tr[op][x][y]+=val;
	}
	int Query(int x,int Y,int op)
	{
		int ret=0;
		for(;x;x-=lowbit(x))
			for(int y=Y;y;y-=lowbit(y)) ret+=tr[op][x][y];
		return ret;
	}
	void Clear(){memset(tr,0,sizeof(tr));}
}BIT;
int Ans[100005];
int main() {
//	freopen("planning.in","r",stdin);
//	freopen("planning.out","w",stdout);
	read(n);read(q);
	for(int qwq=1;qwq<=q;qwq++)
	{
		read(Q[qwq].op);
		if(Q[qwq].op==1)
		{
			read(Q[qwq].dir),read(Q[qwq].x),read(Q[qwq].y),read(Q[qwq].r);
			if(Q[qwq].dir==4) Q[qwq].dir=1; else if(Q[qwq].dir==3) Q[qwq].dir=2;
			else if(Q[qwq].dir==1) Q[qwq].dir=3; else if(Q[qwq].dir==2) Q[qwq].dir=4;
		}
		else read(Q[qwq].x),read(Q[qwq].y);	
	}
	for(int d=1;d<=4;d++)
	{
		BIT.Clear();
		for(int i=1;i<=q;i++)
		{
			if(Q[i].op==1&&Q[i].dir==d)
			{
				int X=Q[i].x,Y=Q[i].y,R=Q[i].r;
				BIT.Add(X-R,X+Y-R,0,1); BIT.Add(X+1,X+Y-R,0,-1);
          		BIT.Add(X-R,Y+1,1,-1); BIT.Add(X+1,Y+1,1,1);
			}
			else if(Q[i].op==2)
			{
				int X=Q[i].x,Y=Q[i].y;
				Ans[i]+=BIT.Query(X,X+Y,0);
				Ans[i]+=BIT.Query(X,Y,1); 
			}
		}
		for(int i=1;i<=q;i++) swap(Q[i].x,Q[i].y),Q[i].x=n+1-Q[i].x;
	}
	for(int i=1;i<=q;i++) if(Q[i].op==2) printf("%d\n",Ans[i]);
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。

曼哈顿转切比雪夫,可以先维护行的前缀和 
以dir=1为例:
维护列的前缀和 
然后就是维护每一行和列的前后缀和 
打差分维护二维前缀和
等等哦,开不下欸
那就不转切比雪夫直接来
*/

再生核希尔伯特空间 / 「CF587F」 Duff is Mad

题意

\(~~~~\) 给出 \(n\) 个字符串,\(q\) 次询问 \([l,r]\) 内的字符串在 \(s_k\) 内共出现了几次。
\(~~~~\) \(1\leq n\leq 2\times 10^5,1\leq \sum |s_i|\leq 2\times 10^5\).

题解

\(~~~~\) 对于这种题,带佬教我:看到这种数据范围就想根号分治/阈值分治。(不过我很怀疑难道不是有了两种做法就开始想这个吗)

\(~~~~\) 那我们先想一些暴力的做法,比如说:如果我们建出AC自动机,那么对于 \(s_k\) 我们将 \(s_k\) 一路上的结点的值都加上 \(1\)。那么对于询问 \([l,r]\) ,实际就是询问 \([l,r]\) 内的字符串在 \(\text{fail}\) 树上的结尾点子树和。当 \(|s_k|\) 非常大的时候这样的询问就很少,我们直接做 \(\mathcal{O(n)}\) 即可。

\(~~~~\) 另一个暴力的想法是降低插入的复杂度。我们求解 \([1,l]\) 的字符串在 \(s_k\) 中出现多少次.插入串的时候我们就把这个串结束结点在 \(\text{fail}\) 树上的子树全部 \(+1\) ,而查询就只能暴力累加 Trie 树上 \(s_k\) 的结束点所有祖先的值。当 \(|s_k|\) 非常小的时候单次复杂度就很优。

\(~~~~\) 具体来说,我们认为当 \(|s_k|>B\) 时采用第一种做法,否则采用第二种做法。记 \(m=\sum_{i=1}^n |s_i|\) 那么复杂度是:\(\mathcal{O(\frac{m^2}{B}+qB\log m)}\) ,那么用均值不等式,得到 \(B=\frac{m}{\sqrt{q \log m}}\)

代码
查看代码
#include <bits/stdc++.h>
#define ll long long
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
ll L[200005],R[200005],Ans[200005];
char S[200005],Tmp[200005];
vector <ll> G[2000005];
vector <PII> Q[2000005];
struct AC_Machine{
	ll ch[200005][27],tot,End[200005],fail[200005];
	AC_Machine(){tot=0;}
	void Insert(ll l,ll r,ll id)
	{
		ll now=0;
		for(ll i=l;i<=r;i++)
		{
			ll To=S[i]-'a'+1;
			if(!ch[now][To]) ch[now][To]=++tot;
			now=ch[now][To];
		}
		End[id]=now;
	}
	void GetFail()
	{
		queue<ll>QQ;
		for(ll i=1;i<=26;i++) if(ch[0][i]) QQ.push(ch[0][i]);
		while(!QQ.empty())
		{
			ll u=QQ.front();QQ.pop();
			for(ll i=1;i<=26;i++)
			{
				if(ch[u][i]) fail[ch[u][i]]=ch[fail[u]][i],QQ.push(ch[u][i]);
				else ch[u][i]=ch[fail[u]][i];
			}
		}
	}
}AC;
ll In[200005],Out[200005],Times,Sum[200005],Sum2[200005];
void dfs(ll u)
{
	In[u]=++Times; 
	for(ll i=0;i<(ll)G[u].size();i++) dfs(G[u][i]);
	Out[u]=Times;
}
struct Ask{
	ll l,r,k;
}A[200005];
struct BIT{
	ll tr[200005];
	inline ll lowbit(ll x){return x&(-x);}
	inline void Add(ll x,ll Val){for(;x<=AC.tot+1;x+=lowbit(x)) tr[x]+=Val;}
	inline ll Query(ll x){ll ret=0;for(;x;x-=lowbit(x)) ret+=tr[x];return ret;}
}BIT;
bool cmp(ll x,ll y){return A[x].k<A[y].k;}
int main() {
//	freopen("rkhs.in","r",stdin);
//	freopen("rkhs.out","w",stdout);
	ll n,m;read(n);read(m);
	for(ll i=1;i<=n;i++)
	{
		scanf("%s",Tmp+1);
		ll len=strlen(Tmp+1);
		L[i]=R[i-1]+1; R[i]=L[i]+len-1;
		for(ll j=L[i];j<=R[i];j++) S[j]=Tmp[j-L[i]+1];
		AC.Insert(L[i],R[i],i);
	}
	AC.GetFail();
	ll B=(ll)R[n]/sqrt(m*log(R[n])/log(2));
	for(ll i=1;i<=AC.tot;i++) G[AC.fail[i]].push_back(i);dfs(0);
	for(ll i=0;i<=AC.tot;i++) reverse(G[i].begin(),G[i].end());
	vector<ll>F;//Big enourh to do force method.
	for(ll i=1,l,r,k;i<=m;i++)
	{
		read(l);read(r);read(k);
		A[i].l=l; A[i].r=r; A[i].k=k;
		if(R[k]-L[k]+1>B) F.push_back(i);
		else Q[l-1].push_back(mp(i,-1)),Q[r].push_back(mp(i,1));
	}
	sort(F.begin(),F.end(),cmp);
	for(ll i=0;i<(ll)F.size();i++)
	{
		if(i==0||A[F[i]].k!=A[F[i-1]].k)
		{
			ll id=A[F[i]].k,now=0;
			memset(Sum,0,sizeof(Sum));
			memset(Sum2,0,sizeof(Sum2));
			for(ll j=L[id];j<=R[id];j++) now=AC.ch[now][S[j]-'a'+1],Sum[In[now]]++;
			for(ll j=1;j<=AC.tot+1;j++) Sum[j]+=Sum[j-1];
			for(ll j=1;j<=n;j++) 
				Sum2[j]=Sum2[j-1]+Sum[Out[AC.End[j]]]-Sum[In[AC.End[j]]-1];
		}
		Ans[F[i]]=Sum2[A[F[i]].r]-Sum2[A[F[i]].l-1];
	}
	for(ll i=1;i<=n;i++)
	{
		BIT.Add(In[AC.End[i]],1); BIT.Add(Out[AC.End[i]]+1,-1);
		for(ll j=0;j<(ll)Q[i].size();j++)
		{
			ll id=Q[i][j].first,Mul=Q[i][j].second,now=0;
			ll ret=0;
			for(ll k=L[A[id].k];k<=R[A[id].k];k++) now=AC.ch[now][S[k]-'a'+1],ret+=BIT.Query(In[now]);
			Ans[id]+=ret*Mul;
		}
	}
	for(ll i=1;i<=m;i++) printf("%lld\n",Ans[i]);
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。
16 1
t
h
dvawooggk
ztqlqgvhzikkynxgbohjcptimzuothen
r
ucqy
rieye
eyklxwlvea
tf
h
chhvhhqro
uhymlqtrxpagbmn
j
hmo
hlzqe
k
6 14 4
*/

鲜花

\(~~~~\) 22:15分时,重庆摆专的高一学生(或许)结束了一天的自习。此时在武汉某OI集训地的会议室,共有11名还在认真自习的学生,其中七名来自重庆摆专(另有两名在自己房间上自习)。

\(~~~~\) 给他们一点小小的摆专震撼。

posted @ 2023-03-07 20:22  Azazеl  阅读(61)  评论(0编辑  收藏  举报