2021.7.13考試總結[NOIP模擬14]
阿新 • • 發佈:2021-07-15
T1隊長快跑 T2影魔 T3跑硬幣
終於考DP了我愛死你了DP
雖然並未切掉一題
T1 隊長快跑
考場n2DP拿了70,看起來很天才但無法延伸到正解。
定義fi,j為考慮到第i個水晶,已摧毀水晶a的最小值為j。
分情況討論,
發現所有操作都可以用線段樹完成,從n2優化到nlogn。
code:
1 #include<bits/stdc++.h> 2 #define debug exit(0) 3 #define ld rt<<1 4 #define rd (rt<<1)|1 5 using namespace std; 6 const int NN=1e5+5; 7T1int n,a[NN],b[NN],has[NN<<1],ext,cnt; 8 inline int read(){ 9 int x=0,f=1; 10 char ch=getchar(); 11 while(ch<'0'||ch>'9'){ 12 if(ch=='-') f=-1; 13 ch=getchar(); 14 } 15 while(ch>='0'&&ch<='9'){ 16 x=(x<<1)+(x<<3)+(ch^48); 17 ch=getchar(); 18 } 19 return x*f; 20 } 21 void write(int x){ 22 if(x<0) x=-x, putchar('-'); 23 if(x>9) write(x/10); 24 putchar(x%10+'0'); 25 } 26 inline int Min(int a,int b){ 27 return a<b?a:b; 28 } 29 inline int Max(int a,int b){ 30 returna<b?b:a; 31 } 32 struct segment_tree{ 33 int maxn[NN<<3],l[NN<<3],r[NN<<3],laz[NN<<3]; 34 void pushup(int rt){ 35 maxn[rt]=Max(maxn[ld],maxn[rd]); 36 } 37 void pushdown(int rt){ 38 if(!laz[rt]) return; 39 laz[ld]+=laz[rt]; laz[rd]+=laz[rt]; 40 maxn[ld]+=laz[rt]; maxn[rd]+=laz[rt]; 41 laz[rt]=0; 42 } 43 void build(int rt,int opl,int opr){ 44 l[rt]=opl; r[rt]=opr; maxn[rt]=0; 45 if(opl==opr) return; 46 int mid=(opl+opr)>>1; 47 build(ld,opl,mid); build(rd,mid+1,opr); 48 } 49 void modify(int rt,int pos,int v){ 50 if(l[rt]==r[rt]){ 51 maxn[rt]=Max(maxn[rt],v); 52 return; 53 } 54 pushdown(rt); 55 int mid=(l[rt]+r[rt])>>1; 56 if(pos<=mid) modify(ld,pos,v); 57 else modify(rd,pos,v); 58 pushup(rt); 59 } 60 void update(int rt,int opl,int opr,int v){ 61 if(l[rt]>=opl&&r[rt]<=opr){ 62 maxn[rt]+=v; 63 laz[rt]+=v; 64 return; 65 } 66 pushdown(rt); 67 int mid=(l[rt]+r[rt])>>1; 68 if(opl<=mid) update(ld,opl,opr,v); 69 if(opr>mid) update(rd,opl,opr,v); 70 pushup(rt); 71 } 72 int query(int rt,int opl,int opr){ 73 if(l[rt]>=opl&&r[rt]<=opr) return maxn[rt]; 74 pushdown(rt); 75 int mid=(l[rt]+r[rt])>>1,ans=0; 76 if(opl<=mid) ans=Max(ans,query(ld,opl,opr)); 77 if(opr>mid) ans=Max(ans,query(rd,opl,opr)); 78 return ans; 79 } 80 }s; 81 void init(){ 82 n=read(); 83 for(int i=1;i<=n;i++) 84 has[++cnt]=a[i]=read(), has[++cnt]=b[i]=read(); 85 sort(has+1,has+cnt+1); 86 ext=unique(has+1,has+cnt+1)-has-1; 87 for(int i=1;i<=n;i++){ 88 a[i]=lower_bound(has+1,has+ext+1,a[i])-has; 89 b[i]=lower_bound(has+1,has+ext+1,b[i])-has; 90 } 91 s.build(1,1,ext); 92 } 93 int main(){ 94 init(); 95 for(int i=1;i<=n;i++) 96 if(a[i]<=b[i]) 97 s.modify(1,a[i],s.query(1,b[i]+1,ext)+1); 98 else{ 99 s.update(1,b[i]+1,a[i],1); 100 s.modify(1,a[i],s.query(1,a[i]+1,ext)+1); 101 } 102 write(s.maxn[1]); putchar('\n'); 103 return 0; 104 }
T2 影魔
有點超綱的主席樹。(其實線段樹合併就能做
先不考慮深度限制,問題可以通過DFS序建線段樹差分解決。
在兩種相同顏色節點的LCA處-1並向上維護即可。
考慮深度限制,按深度順序將節點一層一層插入到主席樹中,查詢是直接查詢相應深度版本的主席樹即可。
code:
1 #include<bits/stdc++.h> 2 #define db exit(0) 3 using namespace std; 4 const int NN=1e5+5; 5 int n,m,num,u,d,cnt,c[NN],to[NN],nex[NN],head[NN],maxd; 6 int id[NN],dfn[NN],dep[NN],fa[NN],top[NN],son[NN],siz[NN]; 7 set<int>sol[NN]; 8 vector<int>nod[NN]; 9 inline int read(){ 10 int x=0,f=1; 11 char ch=getchar(); 12 while(ch<'0'||ch>'9'){ 13 if(ch=='-') f=-1; 14 ch=getchar(); 15 } 16 while(ch>='0'&&ch<='9'){ 17 x=(x<<1)+(x<<3)+(ch^48); 18 ch=getchar(); 19 } 20 return x*f; 21 } 22 void write(int x){ 23 if(x<0) putchar('-'), x=-x; 24 if(x>9) write(x/10); 25 putchar(x%10+'0'); 26 } 27 inline void add(int a,int b){ 28 to[++num]=b; nex[num]=head[a]; head[a]=num; 29 } 30 void dfs1(int f,int st){ 31 siz[st]=1; 32 dep[st]=dep[f]+1; fa[st]=f; 33 maxd=max(maxd,dep[st]); 34 for(int i=head[st];i;i=nex[i]){ 35 int v=to[i]; 36 dfs1(st,v); 37 siz[st]+=siz[v]; 38 if(siz[v]>siz[son[st]]) son[st]=v; 39 } 40 } 41 void dfs2(int st,int t){ 42 top[st]=t; 43 dfn[st]=++cnt; id[cnt]=st; 44 nod[dep[st]].push_back(dfn[st]); 45 if(!son[st]) return; 46 dfs2(son[st],t); 47 for(int i=head[st];i;i=nex[i]){ 48 int v=to[i]; 49 if(v!=fa[st]&&v!=son[st]) dfs2(v,v); 50 } 51 } 52 inline int LCA(int x,int y){ 53 int fx=top[x],fy=top[y]; 54 while(fx!=fy) 55 if(dep[fx]>dep[fy]) x=fa[fx], fx=top[x]; 56 else y=fa[fy], fy=top[y]; 57 return dep[x]<dep[y]?x:y; 58 } 59 struct hjt_segmenttree{ 60 int root[NN*60],lc[NN*60],rc[NN*60],cnt[NN*60],tot; 61 void pushup(int rt){ 62 cnt[rt]=cnt[lc[rt]]+cnt[rc[rt]]; 63 } 64 void update(int &rt,int fom,int l,int r,int pos,int v){ 65 rt=++tot; 66 lc[rt]=lc[fom]; rc[rt]=rc[fom]; 67 cnt[rt]=cnt[fom]; 68 if(l==r){ cnt[rt]+=v; return; } 69 int mid=(l+r)>>1; 70 if(pos<=mid) update(lc[rt],lc[fom],l,mid,pos,v); 71 else update(rc[rt],rc[fom],mid+1,r,pos,v); 72 pushup(rt); 73 } 74 int query(int rt,int l,int r,int opl,int opr){ 75 if(!rt) return 0; 76 if(l>=opl&&r<=opr) return cnt[rt]; 77 int mid=(l+r)>>1,ans=0; 78 if(opl<=mid) ans+=query(lc[rt],l,mid,opl,opr); 79 if(opr>mid) ans+=query(rc[rt],mid+1,r,opl,opr); 80 return ans; 81 } 82 }s; 83 int main(){ 84 n=read(); m=read(); dep[1]=1; 85 for(int i=1;i<=n;i++) c[i]=read(); 86 for(int i=2;i<=n;i++) add(read(),i); 87 dfs1(0,1); dfs2(1,1); 88 for(int de=1;de<=maxd;de++){ 89 for(int i=0;i<nod[de].size();i++){ 90 int fom=!i?de-1:de; 91 int node=id[nod[de][i]]; 92 int col=c[node],pre,nex; 93 s.update(s.root[de],s.root[fom],1,n,nod[de][i],1); 94 sol[col].insert(nod[de][i]); 95 pre=sol[col].find(nod[de][i])==sol[col].begin()?0:*--sol[col].find(nod[de][i]); 96 nex=++sol[col].find(nod[de][i])==sol[col].end()?0:*++sol[col].find(nod[de][i]); 97 if(pre) s.update(s.root[de],s.root[de],1,n,dfn[LCA(node,id[pre])],-1); 98 if(nex) s.update(s.root[de],s.root[de],1,n,dfn[LCA(node,id[nex])],-1); 99 if(pre&&nex) s.update(s.root[de],s.root[de],1,n,dfn[LCA(id[pre],id[nex])],1); 100 } 101 } 102 while(m--){ 103 u=read(); d=read(); 104 write(s.query(s.root[min(maxd,dep[u]+d)],1,n,dfn[u],dfn[u]+siz[u]-1)); 105 putchar('\n'); 106 } 107 return 0; 108 }T2
T3 拋硬幣
DP,fi,j類似T1,每個點可以選或不選,fi,j=fi-1,j+fi-1,j-1。
但需要保證本質不同,因此要記錄每個字母出現的上一個位置p,轉移時減去fp-1,j-1。
code:
1 #include<bits/stdc++.h> 2 #define rin register int 3 #define debug exit(0) 4 using namespace std; 5 const int NN=3005,p=998244353; 6 int len,l,f[NN][NN],pre[NN],pla[30]; 7 char s[NN]; 8 inline int read(){ 9 int x=0,f=1; 10 char ch=getchar(); 11 while(ch<'0'||ch>'9'){ 12 if(ch=='-') f=-1; 13 ch=getchar(); 14 } 15 while(ch>='0'&&ch<='9'){ 16 x=(x<<1)+(x<<3)+(ch^48); 17 ch=getchar(); 18 } 19 return x*f; 20 } 21 void write(int x){ 22 if(x<0) x=-x, putchar('-'); 23 if(x>9) write(x/10); 24 putchar(x%10+'0'); 25 } 26 int main(){ 27 scanf("%s",s+1); l=read(); 28 len=strlen(s+1); 29 for(int i=1;i<=len;i++){ 30 int now=s[i]-'a'+1; 31 pre[i]=pla[now]; 32 pla[now]=i; 33 } 34 for(int i=0;i<=len;i++) f[i][0]=1; 35 for(int i=1;i<=len;i++) 36 for(int j=1;j<=l;j++){ 37 f[i][j]=(f[i-1][j]+f[i-1][j-1])%p; 38 if(pre[i]) f[i][j]=(f[i][j]-f[pre[i]-1][j-1]+p)%p; 39 } 40 write(f[len][l]); putchar('\n'); 41 return 0; 42 }T3