21杭电多校第十场

C

注意到最后一段连续的可行答案其实很长

记录一下对于每个\(i\)来说最后一段连续的起始位置然后暴力转移

#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 1001001
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b))%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int vis[MAXN],las[MAXN];
vector<int> ans[750];
int main()
{
	ans[1].pb(0);
	rep(i,2,700)
	{
		ans[i].pb(0);las[i]=las[i-1]+i-1;
		rep(j,1,i-1) for(auto x:ans[j]) if(!vis[x+j*(i-j)]&&(x+j*(i-j)<=las[i]))
			{ans[i].pb(x+j*(i-j));vis[x+j*(i-j)]=1;}
		sort(ans[i].begin(),ans[i].end());
		dwn(j,ans[i].size()-1,0)
			if(j==ans[i].size()-1||ans[i][j]+1==ans[i][j+1]) las[i]=ans[i][j];
			else break;
		for(auto x:ans[i]) vis[x]=0;
	}
	rep(T,1,read())
	{
		int n=read();
		for(auto x:ans[n]) if(x>las[n]) break;else printf("%d ",x);
		rep(i,las[n]+1,n*(n-1)/2) printf("%d%c",i,i==n*(n-1)/2?'\n':' ');
	}
}

D

朴素的容斥复杂度为\(O(T2^{16})\)无法通过

由于前\(8\)个质数的积\(lim\)很小,可以预处理出\([1,lim]\)中所有数是否是前\(8\)个质数的倍数

对于一个数\(n\)来说,令\(f_n\)表示\(\le n\)的数中不是前八个质数倍数的数的个数,则\(f_n=\lfloor\frac{n}{lim}\rfloor\cdot f_{lim}+f_{n\%lim}\)

因此只需要在此基础上容斥后\(k-8\)个质数即可

#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 10010010
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b))%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int lim=9699690;
int f[MAXN],k;ll n,ans;
int p[20]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
void mem(int n=lim) 
{
	rep(i,0,7) for(int j=p[i];j<=lim;j+=p[i]) f[j]=1;
	rep(i,1,lim-1) f[i]=f[i-1]+(1-f[i]);
}
inline ll calc(ll n)
{
	return n/lim*f[lim-1]+f[n%lim];
}
int main()
{
	mem();int mxs,val;ll now;
	rep(T,1,read())
	{
		n=read(),k=read();ans=0;
		if(k<=8) 
		{
			mxs=(1<<k)-1;
			rep(i,0,mxs)
			{
				now=val=1;
				rep(j,0,k-1) if((i>>j)&1) now*=p[j],val=-val;
				ans+=n/now*val;
			}
		}
		else
		{
			mxs=(1<<k-8)-1;
			rep(i,0,mxs)
			{
				now=val=1;
				rep(j,0,k-1) if((i>>j)&1) now*=p[j+8],val=-val;
				ans+=calc(n/now)*val;
			}
		}
		printf("%lld\n",ans);
	}
}

H

问题即为有多少个位置\(i\)满足\(s[1:x]\)\(s[1:i]\)的后缀且\(s[n-y+1:n]\)\(s[i+1:n]\)的前缀

即询问有多少个前缀满足前缀\(x\)是它的后缀,建出\(kmp\)树之后相当于求多少个\(i\)\(x\)的子树内

后缀同理,问题转化为二维数点问题,横坐标为前缀\(i\)在前缀\(kmp\)树的\(dfs\)序,纵坐标为后缀\(i+1\)在后缀\(kmp\)树中的

每次查询为一个矩形,用主席树可以解决

#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 200100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b))%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,q,g[MAXN],nxt[MAXN],in[MAXN][2],ou[MAXN][2],dfn;
int rt[MAXN],w[MAXN<<6],ls[MAXN<<6],rs[MAXN<<6],tot;
vector<int> G[MAXN];
char s[MAXN];
void dfs(int x,int t)
{
	if(x) in[!t?x:n+1-x][t]=++dfn;
	for(auto v:G[x]) dfs(v,t);
	if(x) ou[!t?x:n+1-x][t]=dfn;
}
void kmp(int t)
{
	int j=0;rep(i,2,n)
	{
		while(j&&s[j+1]!=s[i]) j=nxt[j];
		if(s[j+1]==s[i]) j++;nxt[i]=j;
	}
	rep(i,0,n) G[i].clear();
	rep(i,1,n) G[nxt[i]].pb(i);
	dfn=0;dfs(0,t);
}
bool cmp(int x,int y){return in[x][0]<in[y][0];}
void mdf(int &k,int kk,int l,int r,int x)
{
	w[k=++tot]=w[kk]+1,ls[k]=ls[kk],rs[k]=rs[kk];
	if(l==r) return ;int mid=l+r>>1;
	x<=mid?mdf(ls[k],ls[kk],l,mid,x):mdf(rs[k],rs[kk],mid+1,r,x);
}
int query(int k,int kk,int l,int r,int a,int b)
{
	if(!k) return 0;if(a<=l&&r<=b) return w[k]-w[kk];
	int mid=l+r>>1,res=0;
	if(a<=mid) res=query(ls[k],ls[kk],l,mid,a,b);
	if(b>mid) res+=query(rs[k],rs[kk],mid+1,r,a,b);
	return res;
}
inline void buildt()
{
	rep(i,1,n) g[i]=i;
	sort(g+1,g+n+1,cmp);
	rep(i,1,n)
		if(g[i]==n) rt[i]=rt[i-1];
		else mdf(rt[i],rt[i-1],1,n,in[g[i]+1][1]);
}
int main()
{
	int x,y;rep(T,1,read()) 
	{
		n=read(),q=read();scanf("%s",s+1);
		kmp(0);rep(i,1,n>>1) swap(s[i],s[n+1-i]);
		kmp(1);buildt();
		while(q--)
		{
			x=read(),y=read(),y=n+1-y;
			printf("%d\n",query(rt[ou[x][0]],rt[in[x][0]-1],1,n,in[y][1],ou[y][1]));
		}
		for(;tot;tot--) ls[tot]=rs[tot]=w[tot]=0;
	}
}
posted @ 2021-08-20 15:10  jack_yyc  阅读(54)  评论(0编辑  收藏  举报