21杭電多校第十場
阿新 • • 發佈:2021-08-20
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; } }