1. 程式人生 > 其它 >21杭電多校第十場

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;
	}
}