1. 程式人生 > 其它 >2021.7.13考試總結[NOIP模擬14]

2021.7.13考試總結[NOIP模擬14]

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;
  7
int 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 return
a<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 }
T1

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