「考试总结」20200724初音

A.字符串识别

Description

link

Solution

这题问题出在了对于一个后缀自动机,这里如果在 (DAG) 上面进行操作,复杂度是 (O(n^2))

所以我们换个思路做,还是考虑那些 (endpos) 集合大小为 (1) 的字符串

看看贡献:

[iin [i-len_{fa_i}+1,i] ans_i=min(ans_i,len_{fa_i}+1) ]

[iin[i-len_i+1,i-len_{fa_i}] ans_i=min(ans_i,len_p-i+1) ]

对于第一种情况,线段树统计答案

对于第二种情况,观察到 (ans_i) 这一项总是加着一个 (i)

那么先统一加上,然后最后面减掉,对位置减就好的

另外,区间取 (min) 的线段树,需要好好记得怎么写……

Code

#include<bits/stdc++.h>
using namespace std;
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=5e5+10,M=15e5+10;
	int ans[N],le;
	struct SGT{
		int maxx[N<<2];
		#define maxx(p) maxx[p]
		inline void build(int p,int l,int r,int val)
		{
			if(l==r) return maxx(p)=le+l*val,void();
			int mid=(l+r)>>1; build(p<<1,l,mid,val); build(p<<1|1,mid+1,r,val);
			return maxx(p)=2e9+10,void();
		}
		inline void update(int p,int st,int ed,int l,int r,int val)
		{
			if(l<=st&&ed<=r) return maxx(p)=min(maxx(p),val),void();
			int mid=(st+ed)>>1; 
			if(l<=mid) update(p<<1,st,mid,l,r,val);
			if(r>mid) update(p<<1|1,mid+1,ed,l,r,val); 
			return ;
		}		
		inline void work(int p,int st,int ed,int val)
		{
			if(st==ed)
			{
				ans[st]=min(ans[st],maxx(p)-val*st);
				return ;
			} 
			int mid=(st+ed)>>1;
			maxx(p<<1)=min(maxx(p<<1),maxx(p));
			maxx(p<<1|1)=min(maxx(p<<1|1),maxx(p));
			work(p<<1,st,mid,val); work(p<<1|1,mid+1,ed,val);
			return ;
		}
	}T1,T2;
	struct edg{
		int to,nxt;
	}e[M<<1];
	int head[M],cnt;
	inline void add(int u,int v)
	{
		e[++cnt].to=v; e[cnt].nxt=head[u];
		return head[u]=cnt,void();
	}
	int son[M][26],fa[M],len[M],tot=1,r[M],las=1,sz[M];
	inline void copy(int x,int y)
	{
		for(int i=0;i<26;++i) son[x][i]=son[y][i];
		return ;
	} 
	inline void extend(int x,int id)
	{
		int tmp=las,np=las=++tot; len[np]=len[tmp]+1; sz[np]=1; r[np]=id;
		while(tmp&&!son[tmp][x]) son[tmp][x]=np,tmp=fa[tmp];
		if(!tmp) return fa[np]=1,void();
		int q=son[tmp][x];
		if(len[q]==len[tmp]+1) return fa[np]=q,void();
		int clone=++tot; len[clone]=len[tmp]+1;
		fa[clone]=fa[q],fa[np]=fa[q]=clone; copy(clone,q); r[clone]=x;
		while(tmp&&son[tmp][x]==q) son[tmp][x]=clone,tmp=fa[tmp];
 		return ;
	} 
	inline void dfs(int x)
	{
		for(int i=head[x];i;i=e[i].nxt)
		{
			int t=e[i].to; dfs(t); 
			sz[x]+=sz[t];
		}
		if(sz[x]==1) 
		{
			T1.update(1,1,le,r[x]-len[fa[x]]+1,r[x],len[fa[x]]+1);
			T2.update(1,1,le,r[x]-len[x]+1,r[x]-len[fa[x]],len[x]+1);
		}
		return ;
	}	
	char s[N];
	signed main()
	{
		memset(ans,0x3f,sizeof(ans));
		scanf("%s",s+1); le=strlen(s+1); 
		T1.build(1,1,le,0); 
		T2.build(1,1,le,1); 
		for(int i=1;i<=le;++i) extend(s[i]-'a',i); 
		for(int i=1;i<=tot;++i) add(fa[i],i); dfs(1);
		T1.work(1,1,le,0); 
		T2.work(1,1,le,1);
		for(int i=1;i<=le;++i) printf("%d
",ans[i]);
		return 0;
	}
}
signed main(){return yspm::main();}

B. CQOI2015 选数

Descripion

[sum_{a_1=L}^R sum_{a_2=L}^Rdotssum_{a_n=L}^R [gcd(a_1,a_2,a_3,dots,a_n)=k] (mod 10^9+7) ]

所有参量满足 (le 10^9)

Solution

式子真难看,反手一推变成

[sum_{i=1}^{lfloor frac R k floor} mu(i) (lfloor frac {lfloor frac R k floor} i floor-frac {lfloor frac L k floor} i floor)^n ]

(考试的时候推错式子了……然后外加一些手残就爆零了)

其实搞几个变量代替一下就没这么麻烦了……

然后我们发现这种做法需要开不下的空间做 (mu)

然后去学了一下杜教筛就做完了

或者容斥大佬会这种做法

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define inf (int)1e18+10
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int mod=1e9+7;
	inline int ksm(int x,int y)
	{
		int res=1; 
		for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod;
		return res;
	}
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	const int N=7e6+10;
	bool fl[N];
	int pri[N],cnt,mu[N],n,l,h,k,ans,low,up;
	inline void prework()
	{
		mu[1]=1;
		for(int i=2;i<N;++i) 
		{
			if(!fl[i]) pri[++cnt]=i,mu[i]=mod-1;
			for(int j=1;j<=cnt&&i*pri[j]<N;++j) 
			{
				fl[i*pri[j]]=1;
				if(i%pri[j]==0){mu[i*pri[j]]=0; break;}
				else mu[i*pri[j]]=-mu[i],mu[i*pri[j]]=(mu[i*pri[j]]+mod)%mod;
			}
		} 
		for(int i=1;i<N;++i) mu[i]=add(mu[i],mu[i-1]);
		return ;
	}
	map<int,int> mp;
	inline void calc(int x,int &ans)
	{
		if(x<N) return ans=mu[x],void();
		if(mp[x]) return ans=mp[x],void();
		ans=1; 
		for(int l=2,r,s=0;l<=x;l=r+1)
		{
			r=x/(x/l); s=0;
			calc(x/l,s);
			(s+=mod)%mod;
			ans-=(r-l+1)*s%mod; 
			ans=add(ans,mod);
		} return mp[x]=ans,void();
	}
	inline int ask(int x)
	{
		int ans=0; calc(x,ans); return ans;
	}
	signed main()
	{
		n=read(); k=read(); l=read(); h=read();
		low=(l-1)/k; up=h/k;
		if(low>up) return puts("0"),0;
		prework(); 
		for(int i=1,j;i<=up;i=j+1)
		{
			j=min(low/i?low/(low/i):inf,up/(up/i));
			ans=add(ans,(ask(j)-ask(i-1)+mod)%mod*ksm(up/i-low/i,n)%mod);
		} cout<<ans<<endl;
		return 0;
	}
}
signed main(){return yspm::main();}

C.树点涂色

(sb) 的一个题目了,不到二十天之前刚刚做完,然后今天就忘记了

不写了,直接贴link

总结

感觉上午状态很诡异,上手记错了一个结论,线段树写了一个多小时,还妄想自己能 (AK) 结果呢?

(20)

好好的 (lct) 不会打,反演的式子还推错

我服了我自己,慢慢考试慢慢进步吧

原文地址:https://www.cnblogs.com/yspm/p/13373158.html