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