冲刺国赛7.18


T1

先分类讨论把 /(/max/) 拆开

假设 /(a_c+b_c/geq a_y+b_y/)

/(a_c-a_y/geq b_y-b_c/)

于是对于每个蛋糕都记录一个判据量 /(h/)

属于 /(L/) 的判据为 /(c-y/) 属于 /(C/) 的是 /(y-c/)

当 /(a/) 的判据大于等于 /(b/) 的时候取最小的 /(b_c/)

再开一个关于 /(h/) 值域的线段树,叶子节点用 /(/text{multiset}/) 维护最小的 /(c/) 和 /(y/)

合并时根据判据的大小分别从左右儿子中取 /(c/) 和 /(y/)

在叶子节点时,两个判据相当也可以取最小值

Code
#include<bits/stdc++.h>
#define int long long
#define lson rt<<1
#define rson rt<<1|1
#define inf 0x3f3f3f3f3f3f3f3f
#define meow(args...) fprintf(stderr,args)
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
bool mem1;
int n,rt,tot;
int O[2000010],cnt;
int op[1000010],d[1000010],c[1000010],y[1000010],pos[1000010];
struct seg{int mnc[2],mny[2],ans;}st[1000010*4];
multiset<int>s[1000010][2][2];//pos l/c c/y
inline void pushup(int rt){
	st[rt].ans=min(st[lson].ans,st[rson].ans);
	st[rt].ans=min(st[rt].ans,st[lson].mnc[1]+st[rson].mnc[0]);
	st[rt].ans=min(st[rt].ans,st[lson].mny[0]+st[rson].mny[1]);
	st[rt].mnc[0]=min(st[lson].mnc[0],st[rson].mnc[0]);
	st[rt].mny[0]=min(st[lson].mny[0],st[rson].mny[0]);
	st[rt].mnc[1]=min(st[lson].mnc[1],st[rson].mnc[1]);
	st[rt].mny[1]=min(st[lson].mny[1],st[rson].mny[1]);
}
void upd(int rt,int l,int r,int pos,int i){
	if(l==r){
		if(op[i]==1){
			s[l][d[i]][0].insert(c[i]);st[rt].mnc[d[i]]=*s[l][d[i]][0].begin();
			s[l][d[i]][1].insert(y[i]);st[rt].mny[d[i]]=*s[l][d[i]][1].begin();
		}
		if(op[i]==0){
			s[l][d[i]][0].erase(s[l][d[i]][0].find(c[i]));if(!s[l][d[i]][0].empty()) st[rt].mnc[d[i]]=*s[l][d[i]][0].begin();else st[rt].mnc[d[i]]=inf;
			s[l][d[i]][1].erase(s[l][d[i]][1].find(y[i]));if(!s[l][d[i]][1].empty()) st[rt].mny[d[i]]=*s[l][d[i]][1].begin();else st[rt].mny[d[i]]=inf;
		}
		st[rt].ans=min(st[rt].mnc[0]+st[rt].mnc[1],st[rt].mny[0]+st[rt].mny[1]);
		return ;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) upd(lson,l,mid,pos,i);
	else upd(rson,mid+1,r,pos,i);
	pushup(rt);
}
bool mem2;
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("cake.in","r",stdin);
	freopen("cake.out","w",stdout);
	n=read();memset(st,0x3f,sizeof(st));
	for(int i=1;i<=n;i++){
		op[i]=read(),d[i]=read(),c[i]=read(),y[i]=read();
		if(d[i]==0) O[++cnt]=pos[i]=c[i]-y[i];
		if(d[i]==1) O[++cnt]=pos[i]=y[i]-c[i];
	}
	sort(O+1,O+1+cnt);cnt=unique(O+1,O+1+cnt)-O-1;
	for(int i=1;i<=n;i++) pos[i]=lower_bound(O+1,O+1+cnt,pos[i])-O;
	for(int i=1;i<=n;i++){
		upd(1,1,cnt,pos[i],i);
		printf("%lld/n",st[1].ans<=2000000000?st[1].ans:-1ll);
	}	
	return 0;
}

T2

一行一行的转移,设 /(f_i=[i/in S]/)

发现如果 /(b/) 只有一种转移

那就是普通的位运算卷积

现在有很多种 /(b/) 发现每一位和每一位之间是不影响的

所以可以按位考虑,根据当前位的 /(b/) 去做 /(/text{fwt}/)

然后行与行之间的转移都是相同的,于是再做个快速幂

Code
#include<bits/stdc++.h>
#define int long long
#define i2 500000004
#define mod 1000000007
#define inf 0x3f3f3f3f3f3f3f3f
#define meow(args...) fprintf(stderr,args)
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,q,len;
int a[1048576],b[1048576];
char s[1048576];
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
	return res;
}
inline void fwt(int tx){
	for(int d=1,bit=0;d<len;d<<=1,bit++) for(int i=0;i<len;i+=d<<1) for(int j=0;j<d;j++){
		int x=a[i+j],y=a[i+j+d];
		if(b[bit]==1) (a[i+j+d]+=a[i+j]*tx)%=mod;
		if(b[bit]==2) (a[i+j]+=a[i+j+d]*tx)%=mod;
		if(b[bit]==3){
			a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;
			if(tx==mod-1) a[i+j]=a[i+j]*i2%mod,a[i+j+d]=a[i+j+d]*i2%mod;
		}
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("completion.in","r",stdin);
	freopen("completion.out","w",stdout);

	n=read(),m=read();scanf("%s",s);len=1<<m;
	for(int i=0;i<m;i++) b[i]=read();
	for(int i=0;i<len;i++) a[i]=s[i]-'0';
	
	fwt(1);
	for(int i=0;i<len;i++) a[i]=qpow(a[i],n);
	fwt(mod-1);
	
	q=read();
	for(int i=1;i<=q;i++) printf("%lld/n",a[read()]);
	return 0;
}

T3

找两个前缀的最长后缀,可以用 /(/text{SAM}/)

直接找他们两个前缀代表的节点在 /(/text{parent}/) 树上的 /(/text{LCA}/) 就是他们的最长后缀

现在要找的就是两两之间的最长前缀,可以把这些节点代表的串建出 /(/text{Trie}/)

然后最长前缀的长度就是 /(/text{LCA}/) 的深度,然后就变成了一个经典问题,可以用树剖做

现在瓶颈在于建 /(/text{Trie}/)

发现这颗 /(/text{Trie}/) 的节点很少,且和 /(/text{SAM}/) 上的节点一一对应

于是直接枚举 /(/text{SAM}/) 上的每条边,如果两个节点代表的长度正好差 /(1/) 就说明是 /(/text{Trie}/) 上的边

Code
#include<bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f3f3f3f3f3f
#define meow(args...) fprintf(stderr,args)
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,q,tot=1,lst=1,ans;
int pos[500010];
char s[500010];
bool vis[1000010];
namespace Trie{
	int c1[1000010],c2[1000010];
	int fa[1000010],son[1000010],dep[1000010],siz[1000010],top[1000010],dfn[1000010],clo;
	int head[1000010],ver[1000010],to[1000010],cnt;
	inline void add(int x,int y){
		ver[++cnt]=y;to[cnt]=head[x];head[x]=cnt;
	}
	inline void ins(int l,int r,int k){
		for(int w=(l-1)*k;l<=tot;l+=l&-l) c1[l]+=k,c2[l]+=w;r++;
		for(int w=(r-1)*k;r<=tot;r+=r&-r) c1[r]-=k,c2[r]-=w;
	}
	inline int query(int l,int r){
		int res=0;
		for(int w=r;r;r-=r&-r) res+=c1[r]*w-c2[r];l--;
		for(int w=l;l;l-=l&-l) res-=c1[l]*w-c2[l];
		return res;
	}
	void dfs1(int x,int fath,int depth){
		fa[x]=fath,dep[x]=depth,siz[x]=1;
		int maxson=-1;
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];dfs1(y,x,depth+1);
			siz[x]+=siz[y];
			if(siz[y]>maxson) maxson=siz[y],son[x]=y;
		}
	}
	void dfs2(int x,int topf){
		dfn[x]=++clo;
		top[x]=topf;if(!son[x]) return;
		dfs2(son[x],topf);
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];if(y==son[x]) continue;
			dfs2(y,y);
		}
	}
	inline void upd(int x,int k){
		while(top[x]!=1) ins(dfn[top[x]],dfn[x],k),x=fa[top[x]];
		if(dfn[x]>1) ins(dfn[1]+1,dfn[x],k);
	}
	inline int query(int x){
		int res=0;
		while(top[x]!=1) res+=query(dfn[top[x]],dfn[x]),x=fa[top[x]];
		res+=query(dfn[1],dfn[x]);
		return res;
	}
}
namespace SAM{
	struct node{int len,fa,son[4];}t[1000010];
	int fa[1000010],son[1000010],dep[1000010],siz[1000010],top[1000010];
	int head[1000010],ver[1000010],to[1000010],cnt;
	inline void add(int x,int y){
		ver[++cnt]=y;to[cnt]=head[x];head[x]=cnt;
	}
	inline void extend(int c,int u){
		int p=++tot,f=lst;lst=p;
		t[p].len=t[f].len+1;pos[u]=p;
		while(f&&!t[f].son[c]) t[f].son[c]=p,f=t[f].fa;
		if(!f) return t[p].fa=1,void();
		int x=t[f].son[c],y=++tot;
		if(t[f].len+1==t[x].len) return tot--,t[p].fa=x,void();
		t[y]=t[x];t[y].len=t[f].len+1,t[x].fa=t[p].fa=y;
		while(f&&t[f].son[c]==x) t[f].son[c]=y,f=t[f].fa;
	}
	void dfs1(int x,int fath,int depth){
		fa[x]=fath,dep[x]=depth,siz[x]=1;
		int maxson=-1;
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];dfs1(y,x,depth+1);
			siz[x]+=siz[y];
			if(siz[y]>maxson) maxson=siz[y],son[x]=y;
		}
	}
	void dfs2(int x,int topf){
		top[x]=topf;if(!son[x]) return;
		dfs2(son[x],topf);
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];if(y==son[x]) continue;
			dfs2(y,y);
		}
	}
	inline int LCA(int x,int y){
		while(top[x]!=top[y]) (dep[top[x]]>dep[top[y]])?x=fa[top[x]]:y=fa[top[y]];
		return (dep[x]<dep[y])?x:y;
	}
	void build(){
		for(int i=2;i<=tot;i++) add(t[i].fa,i);
		for(int i=1;i<=tot;i++) for(int j=0;j<4;j++) if(t[i].son[j]) if(t[i].len+1==t[t[i].son[j]].len) Trie::add(i,t[i].son[j]);
		dfs1(1,0,1);dfs2(1,1);Trie::dfs1(1,0,1);Trie::dfs2(1,1);
		
		// for(int i=1;i<=tot;i++) printf("t[%lld].len : %lld/n",i,t[i].len);
		// for(int i=1;i<=tot;i++) for(int j=0;j<4;j++) if(t[i].son[j]) printf("%lld -> %lld/n",i,t[i].son[j]);
		// for(int i=1;i<=n;i++) printf("pos[%lld] : %lld/n",i,pos[i]);
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("elixir.in","r",stdin);
	freopen("elixir.out","w",stdout);
	scanf("%s",s+1);n=strlen(s+1);
	for(int i=1;i<=n;i++) SAM::extend(s[i]-'a',i);SAM::build();
	q=read();
	for(int i=1,x,y,z;i<=q;i++){
		x=pos[read()],y=pos[read()];
		z=SAM::LCA(x,y);
		if(vis[z]){
			vis[z]=0,Trie::upd(z,-1),ans-=Trie::query(z);
		}else{
			vis[z]=1,ans+=Trie::query(z),Trie::upd(z, 1);
		}
		printf("%lld/n",ans);
	}
	return 0;
}

原创文章,作者:,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/276636.html

(0)
上一篇 2022年7月24日 10:36
下一篇 2022年7月24日 10:36

相关推荐

发表回复

登录后才能评论