2021.8.16考试总结[NOIP模拟41]

T1 你相信引力吗


肯定是单调栈维护。但存在重复值,还是个环,不好搞。

发现取区间时不会越过最大值,因此以最大值为断点将环断为序列。在栈里维护当前栈中有多少个与当前元素相等的元素,小分类讨论一下。

最后作为最大值的断点可以与栈中剩下的每个元素组成点对。

$code:$

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 const int NN=5e6+5;
 5 int n,m,top,mx,h[NN<<1],stk[NN<<1],cnt[NN<<1];
 6 LL ans;
 7 inline int read(){
 8     int x=0,f=1; char ch=getchar();
 9     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
10     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
11     return x*f;
12 }
13 inline void write(LL x,char sp){
14     char ch[20]; int len=0;
15     if(x<0){ putchar('-'); x=~x+1; }
16     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
17     for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
18 }
19 signed main(){
20     n=read();
21     for(int i=1;i<=n;i++){
22         h[i+n]=h[i]=read();
23         if(h[i]>h[mx]) mx=i;
24     }
25     for(int i=mx;i<mx+n;i++){
26         while(top&&stk[top]<h[i]) --top, ++ans;
27         if(stk[top]>h[i]) ++ans;
28         else ans+=cnt[top]+(h[i]!=h[mx]);
29         stk[++top]=h[i];
30         cnt[top]=(stk[top-1]==h[i])?(cnt[top-1]+1):1;
31     }
32     while(top>2){
33         if(stk[top]==stk[2]) break;
34         --top; ++ans;
35     }
36     write(ans,'\n');
37     return 0;
38 }
T1

T2 marshland


范围$50$,棋盘,带限制,考虑网络流。

 黑白染色,将危险点看作黑点。发现每次覆盖都将占据黑点左右中一个白点,上下中一个白点。让奇偶行白点分列二分图两边即可。

在二分图两列点间插黑点,把黑点拆成入点和出点,中间连费用为危险值的边。跑“最大费用可行流”即可。

$code:$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int NN=1e6+10,inf=2e9;
 4 int to[NN<<1],nex[NN<<1],head[NN],c[NN<<1],w[NN<<1],idx=1;
 5 int s,t,incf[NN],pre[NN],dis[NN],flow,value,ans;
 6 int n,m,k,sum,val[55][55];
 7 bool stp[55][55],vis[NN];
 8 inline int id(int x,int y){ return (x-1)*n+y; }
 9 inline void link(int a,int b,int x,int y){ to[++idx]=b; nex[idx]=head[a]; head[a]=idx; c[idx]=x; w[idx]=y; }
10 inline void add(int a,int b,int x,int y){ link(a,b,x,y); link(b,a,0,-y); }
11 inline int read(){
12     int x=0,f=1; char ch=getchar();
13     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
14     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
15     return x*f;
16 }
17 inline void write(int x,char sp){
18     char ch[20]; int len=0;
19     if(x<0){ putchar('-'); x=~x+1; }
20     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
21     for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
22 }
23 inline bool SPFA(){
24     queue<int>q;
25     memset(dis,-0x3f,sizeof(dis));
26     memset(vis,0,sizeof(vis));
27     q.push(s); dis[s]=0; incf[s]=inf; vis[s]=1;
28     while(!q.empty()){
29         int x=q.front(); q.pop(); vis[x]=0;
30         for(int i=head[x];i;i=nex[i]){
31             if(!c[i]) continue;
32             int v=to[i];
33             if(dis[v]<dis[x]+w[i]){
34                 dis[v]=dis[x]+w[i];
35                 incf[v]=min(incf[x],c[i]);
36                 pre[v]=i;
37                 if(!vis[v]) vis[v]=1, q.push(v);
38             }
39         }
40     }
41     return dis[t]>0;
42 }
43 void MCMF(){
44     while(SPFA()){
45         int i,x=t;
46         if(flow+incf[t]>m) break;
47         flow+=incf[t];
48         value=max(value,value+dis[t]*incf[t]);
49         while(x!=s){
50             i=pre[x];
51             c[i]-=incf[t];
52             c[i^1]+=incf[t];
53             x=to[i^1];
54         }
55     }
56 }
57 signed main(){
58     n=read(); m=read(); k=read(); s=(n*n<<1)+1; t=s+1; idx=1;
59     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) val[i][j]=read(), sum+=val[i][j];
60     for(int i=1;i<=k;i++) stp[read()][read()]=1;
61     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
62         if(stp[i][j]) continue;
63         if((i+j)&1) add(id(i,j),id(i,j)+n*n,1,val[i][j]);
64         else if(i&1){
65             add(s,id(i,j),1,0);
66             if(i>1) add(id(i,j),id(i-1,j),1,0);
67             if(i<n) add(id(i,j),id(i+1,j),1,0);
68             if(j>1) add(id(i,j),id(i,j-1),1,0);
69             if(j<n) add(id(i,j),id(i,j+1),1,0);
70         } else{
71             add(id(i,j),t,1,0);
72             if(i>1) add(id(i-1,j)+n*n,id(i,j),1,0);
73             if(i<n) add(id(i+1,j)+n*n,id(i,j),1,0);
74             if(j>1) add(id(i,j-1)+n*n,id(i,j),1,0);
75             if(j<n) add(id(i,j+1)+n*n,id(i,j),1,0);
76         }
77     }
78     ans=sum; MCMF();
79     write(ans-value,'\n');
80     return 0;
81 }
T2

T3 party?


树形结构,每个人走到所有人的$LCA$。

暴力可以网络流,但我太laji。。(为啥联赛会一场两道网络流???

构造二分图,左边是人,右边是特产,特产连边容量为$1$,二分人与源点连边的容量即为答案。

如果把连边容量为$mid$改为将每个人拆为$mid$个点,问题就转化为求二分图完美匹配。于是有没听说过的霍尔定理:

一个二分图存在完美匹配,当且仅当左部点$x$中任意$k$个点都与右部点$y$中至少$k$个点邻接。

 于是可以不用二分。枚举人的所有子集,用它们对应特产数除以人数,取$min$后即为每人最多能带的特产数。

特产可以用$bitset$加树剖维护。维护一个点到它$top$路径上的特产集合可以在树剖时减少一个$log$。

$code:$

  1 #include<bits/stdc++.h>
  2 #define bst bitset<1024>
  3 using namespace std;
  4 const int NN=3e5+5;
  5 int n,c,m,q,to[NN<<1],nex[NN<<1],head[NN],idx,pla[6],a[NN],ans;
  6 int dep[NN],son[NN],siz[NN],top[NN],dfn[NN],fa[NN],id[NN],cnt;
  7 bst b[NN];
  8 inline int read(){
  9     int x=0,f=1; char ch=getchar();
 10     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 11     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
 12     return x*f;
 13 }
 14 inline void write(int x,char sp){
 15     char ch[20]; int len=0;
 16     if(x<0){ putchar('-'); x=~x+1; }
 17     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
 18     for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
 19 }
 20 inline void add(int a,int b){
 21     to[++idx]=b; nex[idx]=head[a]; head[a]=idx;
 22     to[++idx]=a; nex[idx]=head[b]; head[b]=idx;
 23 }
 24 struct segment_tree{
 25     #define ld rt<<1
 26     #define rd (rt<<1)|1
 27     bst bs[NN<<2];
 28     void pushup(int rt){
 29         bs[rt]=bs[ld]|bs[rd];
 30     }
 31     void build(int rt,int l,int r){
 32         if(l==r){ bs[rt][a[id[l]]]=1; return; }
 33         int mid=l+r>>1;
 34         build(ld,l,mid);
 35         build(rd,mid+1,r);
 36         pushup(rt);
 37     }
 38     bst query(int rt,int l,int r,int opl,int opr){
 39         if(l>=opl&&r<=opr) return bs[rt];
 40         int mid=l+r>>1;
 41         bst tmp;
 42         if(opl<=mid) tmp|=query(ld,l,mid,opl,opr);
 43         if(opr>mid) tmp|=query(rd,mid+1,r,opl,opr);
 44         return tmp;
 45     }
 46 }s;
 47 void dfs1(int s,int f){
 48     fa[s]=f; dep[s]=dep[f]+1; siz[s]=1;
 49     for(int i=head[s];i;i=nex[i]){
 50         int v=to[i];
 51         if(v==f) continue;
 52         dfs1(v,s);
 53         siz[s]+=siz[v];
 54         if(siz[son[s]]<siz[v]) son[s]=v;
 55     }
 56 }
 57 void dfs2(int s,int t){
 58     dfn[s]=++cnt; id[cnt]=s; top[s]=t;
 59     if(s!=t) b[s]=b[fa[s]]; b[s].set(a[s]);
 60     if(!son[s]) return;
 61     dfs2(son[s],t);
 62     for(int i=head[s];i;i=nex[i]){
 63         int v=to[i];
 64         if(v!=fa[s]&&v!=son[s]) dfs2(v,v);
 65     }
 66 }
 67 bst S(int x,int lca){
 68     bst tmp;
 69     while(top[x]!=top[lca]) tmp|=b[x], x=fa[top[x]];
 70     tmp|=s.query(1,1,n,dfn[lca],dfn[x]);
 71     return tmp;
 72 }
 73 inline int LCA(int x,int y){
 74     while(top[x]!=top[y]){
 75         if(dep[top[x]]<dep[top[y]]) swap(x,y);
 76         x=fa[top[x]];
 77     }
 78     return dep[x]<dep[y]?x:y;
 79 }
 80 signed main(){
 81     n=read(); m=read(); q=read();
 82     for(int i=2;i<=n;i++) add(i,read());
 83     for(int i=1;i<=n;i++) a[i]=read();
 84     dfs1(1,0); dfs2(1,1); s.build(1,1,n);
 85     while(q--){
 86         c=read(); ans=INT_MAX;
 87         for(int i=1;i<=c;i++) pla[i]=read();
 88         int lca=LCA(pla[1],pla[2]);
 89         for(int i=3;i<=c;i++) lca=LCA(lca,pla[i]);
 90         bst path[6];
 91         for(int i=1;i<=c;i++) path[i]|=S(pla[i],lca);
 92         for(int i=1;i<1<<c;i++){
 93             path[0].reset();
 94             int cntt=0;
 95             for(int j=0;j<c;j++)
 96                 if(i&(1<<j)) path[0]|=path[j+1], cntt++;
 97             ans=min(ans,(int)path[0].count()/cntt);
 98         }
 99         write(ans*c,'\n');
100     }
101     return 0;
102 }
T3

 

posted @ 2021-08-16 21:28  keen_z  阅读(44)  评论(0编辑  收藏  举报