zoukankan      html  css  js  c++  java
  • csp-s模拟测试50(9.22)「施工(单调栈优化DP)」·「蔬菜(二维莫队???)」·「联盟(树上直径)」

    改了两天,终于将T1,T3毒瘤题改完了...

    T1 施工(单调栈优化DP)

    考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解

    正解是很**的单调栈

    可以想象到最优情况一定是将两端高于中间的一段平原填成一段平的坑,不然如果坑内存在高度差那么我们即使只将一部分抬升也肯定没有用处,并且如果中间的坑已经高于了两端,再向上升也肯定不优,然后就中间的坑可以很很小,也可以很长,对于这个模型我们首先想到n^2*h的DP

    设当前表示的f[i]表示当前到了i节点并且i节点高度不变时的花费,那么能转移到他的其实只有高于i节点高度的点,那么我们

    其实可以考虑用单调栈维护

    然后对于h的最优高度化简后是一个二次函数的形式,然后直接求解就好,然后求二次函数时要注意解的范围,也要注意解是否为整数,然后打了很久..........

     1 #include<bits/stdc++.h>
     2 #define int long long
     3 #define MAXN 110000
     4 #define inf 0x7ffffffffff
     5 using namespace std;
     6 int read(){
     7     int x=0;char cc=getchar();
     8     while(cc<'0'||cc>'9'){cc=getchar();}
     9     while(cc>='0'&&cc<='9'){x=(x<<1)+(x<<3)+(cc^48);cc=getchar();}
    10     return x;
    11 }
    12 struct node{int l,r,sum1,sum2;}t[MAXN*4];
    13 int f[3][MAXN];int a[MAXN];int n;int maxn=0;int c=0;
    14 void build(int k,int l,int r){
    15      t[k].l=l;t[k].r=r;
    16      t[k].sum1=inf;t[k].sum2=inf;
    17      if(l==r)return ;     
    18      int mid=(l+r)>>1;
    19      build(k*2,l,mid);build(k*2+1,mid+1,r);
    20      return ;
    21 }    
    22 int now=1;int last=0;
    23 void change(int k,int x){
    24      if(t[k].l==t[k].r){
    25         t[k].sum1=f[now][x]-x*c;
    26         t[k].sum2=f[now][x]+x*c;
    27         return ;
    28      }
    29      int mid=(t[k].l+t[k].r)>>1;
    30      if(x<=mid){change(k*2,x);}
    31      else change(k*2+1,x);
    32      t[k].sum1=min(t[k*2].sum1,t[k*2+1].sum1);
    33      t[k].sum2=min(t[k*2].sum2,t[k*2+1].sum2);
    34 }
    35 int ask=inf;
    36 void query(int k,int l,int r,int me){
    37      if(t[k].l>=l&&t[k].r<=r){
    38         if(me==1){ask=min(ask,t[k].sum1);}
    39         else{ask=min(ask,t[k].sum2);}
    40         return ;
    41      }
    42      int mid=(t[k].l+t[k].r)>>1;
    43      if(l<=mid)query(k*2,l,r,me);
    44      if(r>mid)query(k*2+1,l,r,me);
    45 }
    46 signed main(){
    47 //freopen("t1.in","r",stdin);
    48 //freopen("tree.out","w",stdout);
    49     memset(f,0x3f3f3f3f,sizeof(f));
    50     n=read();c=read();
    51     for(int i=1;i<=n;++i){a[i]=read(),maxn=max(maxn,a[i]);}
    52     build(1,0,maxn);
    53     for(int i=a[1];i<=maxn;++i){
    54         f[now][i]=(i-a[1])*(i-a[1]);
    55         change(1,i);
    56     }
    57     swap(now,last);
    58     for(int i=2;i<=n;++i){
    59         for(int j=a[i];j<=maxn;++j){
    60             /*for(int k=a[i-1];k<=maxn;++k){
    61                 f[now][j]=min(f[last][k]+c*abs(j-k),f[now][j]);            
    62                 //printf("f[%lld][%lld]=%lld k=%lld f=%lld
    ",i,j,f[now][j],k,f[last][k]);
    63             }
    64             f[now][j]+=(j-a[i])*(j-a[i]);*/
    65             if(a[i-1]<=j){
    66                ask=inf;query(1,a[i-1],j,1);
    67                f[now][j]=min(f[now][j],ask+j*c);
    68                ask=inf;query(1,j+1,maxn,2);
    69                f[now][j]=min(f[now][j],ask-j*c);
    70                f[now][j]+=(j-a[i])*(j-a[i]);
    71             }
    72             else{
    73                ask=inf;query(1,a[i-1],maxn,2);
    74                f[now][j]=ask-c*j;
    75                f[now][j]+=(j-a[i])*(j-a[i]);
    76             }
    77             change(1,j);
    78         }
    79         swap(now,last);
    80         memset(f[now],0x3f3f3f3f,sizeof(f[now]));
    81     }
    82     swap(now,last);
    83     int minn=inf;
    84     for(int i=a[n];i<=maxn;++i){
    85        minn=min(f[now][i],minn);
    86     }
    87     printf("%lld
    ",minn);
    88 }
    暴力
      1 #include<bits/stdc++.h>
      2 #define MAXN 2010000
      3 #define inf 0x7ffffff
      4 using namespace std;
      5 double logg[MAXN];
      6 int read(){
      7     int x=0;char cc=getchar();
      8     while(cc<'0'||cc>'9'){cc=getchar();}
      9     while(cc>='0'&&cc<='9'){x=(x<<1)+(x<<3)+(cc^48);cc=getchar();}
     10     return x;
     11 }
     12 long long minn(long long x,long long y){return (x<y)?x:y;}
     13 int ff[21][MAXN];long long a[MAXN];int n;
     14 int RMB(int l,int r){
     15     int t=logg[r-l+1]/logg[2ll];
     16     return max(ff[t][l],ff[t][r-(1<<t)+1]);
     17 }
     18 void init(){
     19      for(int i=1;i<=n;++i)ff[0][i]=a[i];
     20      for(int j=1;j<=20;++j){
     21          for(int i=1;i+(1<<j)-1<=n;++i){
     22              ff[j][i]=max(ff[j-1][i],ff[j-1][i+(1<<(j-1))]);
     23          }
     24      }
     25 }
     26 int top=0;long long len=0;
     27 long long sum1[MAXN],sum2[MAXN];
     28 long long f[MAXN];int st[MAXN];int c=0;
     29 int jud(int x){
     30     if(x==(n+1)||x==0)return n+2;
     31     return x;
     32 }
     33 int jud1(int x,int y){
     34     if(x==0&&y==n+1)return 0;
     35     else if(x==0||y==n+1)return c;
     36     return (2*c);
     37 }
     38 long long cal(int x,int y){
     39     long long ans=0;
     40     long long s0=(y-x+1);
     41     long long s1=-(sum2[y]-sum2[x-1])*2-jud1(x-1,y+1);
     42     long long s2=sum1[y]-sum1[x-1]+a[jud(y+1)]*c+a[jud(x-1)]*c;
     43     double kx=-((double)s1/(double)(2*s0));
     44     if(kx>minn((double)a[x-1],(double)a[y+1])){
     45        kx=minn((double)a[x-1],(double)a[y+1]);
     46     }
     47     else if(kx<(double)RMB(x,y))kx=(double)RMB(x,y);
     48     if((-s1)%(2*s0)==0){
     49        len=(long long)kx;
     50        ans=s0*len*len+s1*len+s2;
     51        return ans;
     52     }
     53     else{
     54         long long len1=floor(kx);long long len2=ceil(kx);
     55         if(len2>minn(a[x-1],a[y+1]))len2=minn(a[x-1],a[y+1]);
     56         else if(len1<RMB(x,y))len1=RMB(x,y);       
     57         long long ans1=s0*len1*len1+s1*len1+s2;
     58         long long ans2=s0*len2*len2+s1*len2+s2;
     59         if(ans1>ans2){
     60              len=len2;
     61              return ans2;
     62         }
     63         else{
     64             len=len1;
     65             return ans1;
     66         }
     67     }
     68 }
     69 long long ans_len=0;
     70 signed main(){
     71     memset(f,0x3f3f3f3f,sizeof(f));
     72     n=read();c=read();
     73     for(int i=1;i<=n;++i){
     74         a[i]=read();
     75         sum1[i]=sum1[i-1]+a[i]*a[i];
     76         sum2[i]=sum2[i-1]+a[i];
     77     }
     78     init();
     79     for(int i=1;i<=n;++i){
     80         logg[i]=log(i)/log(2);
     81     }
     82     sum1[n+1]=sum1[n];sum2[n+1]=sum2[n];
     83     st[++top]=0;a[0]=inf;a[n+1]=inf-1;
     84     st[++top]=1;f[1]=0;f[0]=0;   
     85     for(int i=2;i<=n+1;++i){
     86         if(i!=n+1)f[i]=min(f[i],f[i-1]+abs(a[i-1]-a[i])*c);
     87         else f[i]=f[i-1];
     88         while(a[st[top]]<=a[i]){
     89               int to=st[top];
     90               if(to+1<=i-1){
     91                  long long kxx=cal(to+1,i-1);
     92                  if(f[to]+kxx<f[i]){
     93                     ans_len=len;f[i]=f[to]+kxx;              
     94                  }
     95               }
     96               top--;
     97         }        
     98         int to1=st[top];
     99         if(to1+1<=i-1){
    100            long long kxx=cal(to1+1,i-1);
    101            if(f[to1]+kxx<f[i]){
    102               ans_len=len;f[i]=f[to1]+kxx;              
    103            }           
    104         }
    105         st[++top]=i;
    106     }              
    107     printf("%lld
    ",f[n+1]);
    108 }
    View Code

    T2 蔬菜

    正解????然后就打暴力吧,二维莫队,时间复杂度不会

      1 #include<bits/stdc++.h>
      2 #define int long long
      3 #define MAXN 210
      4 using namespace std;
      5 int read(){
      6     int x=0;char cc=getchar();
      7     while(cc<'0'||cc>'9'){cc=getchar();}
      8     while(cc>='0'&&cc<='9'){x=(x<<1)+(x<<3)+(cc^48);cc=getchar();}
      9     return x;
     10 }
     11 int a[MAXN][MAXN];int ans=0;int n,m,q;
     12 int tong[MAXN*MAXN];int vis[MAXN*MAXN];
     13 struct node{int x1,x2,y1,y2,id,ans;}e[1000000];
     14 int l_x,r_x,l_y,r_y;
     15 bool cmp(node a,node b){
     16      if(a.x1!=b.x1)return a.x1<b.x1;
     17      if(a.y1!=b.y1)return b.y1<b.y1;
     18      if(a.x2!=b.x2)return a.x2<b.x2;
     19      return a.y2<b.y2;
     20 }
     21 bool cmp1(node a,node b){return a.id<b.id;}
     22 void work_x(int i){
     23      while(l_x<e[i].x1){
     24            for(int j=l_y;j<=r_y;++j){
     25                ans-=tong[a[l_x][j]]*tong[a[l_x][j]];
     26                tong[a[l_x][j]]--;
     27                ans+=tong[a[l_x][j]]*tong[a[l_x][j]];
     28            }
     29            l_x++;
     30      }
     31      while(r_x>e[i].x2){
     32            for(int j=l_y;j<=r_y;++j){
     33                ans-=tong[a[r_x][j]]*tong[a[r_x][j]];
     34                tong[a[r_x][j]]--;
     35                ans+=tong[a[r_x][j]]*tong[a[r_x][j]];               
     36            }
     37            r_x--;
     38      }
     39      while(r_x<e[i].x2){
     40            r_x++;
     41            for(int j=l_y;j<=r_y;++j){
     42                ans-=tong[a[r_x][j]]*tong[a[r_x][j]];
     43                tong[a[r_x][j]]++;
     44                ans+=tong[a[r_x][j]]*tong[a[r_x][j]];               
     45            }     
     46      }
     47 }
     48 void work_y(int i){
     49      while(l_y<e[i].y1){
     50            for(int j=l_x;j<=r_x;++j){
     51                ans-=tong[a[j][l_y]]*tong[a[j][l_y]];
     52                tong[a[j][l_y]]--;
     53                ans+=tong[a[j][l_y]]*tong[a[j][l_y]];
     54            }
     55            l_y++;
     56      }
     57      while(l_y>e[i].y1){
     58            l_y--;
     59            for(int j=l_x;j<=r_x;++j){
     60                ans-=tong[a[j][l_y]]*tong[a[j][l_y]];
     61                tong[a[j][l_y]]++;
     62                ans+=tong[a[j][l_y]]*tong[a[j][l_y]];
     63            }
     64      }
     65      while(r_y<e[i].y2){
     66            r_y++;
     67            for(int j=l_x;j<=r_x;++j){
     68                ans-=tong[a[j][r_y]]*tong[a[j][r_y]];
     69                tong[a[j][r_y]]++;
     70                ans+=tong[a[j][r_y]]*tong[a[j][r_y]];
     71            }
     72      }
     73      while(r_y>e[i].y2){
     74            for(int j=l_x;j<=r_x;++j){
     75                ans-=tong[a[j][r_y]]*tong[a[j][r_y]];
     76                tong[a[j][r_y]]--;
     77                ans+=tong[a[j][r_y]]*tong[a[j][r_y]];
     78            }
     79            r_y--;
     80      }
     81 }
     82 signed main(){
     83     n=read();m=read();q=read();
     84     for(int i=1;i<=n;++i){
     85         for(int j=1;j<=m;++j){
     86             a[i][j]=read();tong[++tong[0]]=a[i][j];
     87         }
     88     }
     89     sort(tong+1,tong+tong[0]+1);
     90     tong[0]=unique(tong+1,tong+tong[0]+1)-tong-1;
     91     for(int i=1;i<=n;++i){
     92         for(int j=1;j<=m;++j){
     93             a[i][j]=lower_bound(tong+1,tong+tong[0]+1,a[i][j])-tong;
     94         }
     95     }
     96     for(int i=1;i<=q;++i){
     97         e[i].id=i;e[i].x1=read();e[i].y1=read();e[i].x2=read();e[i].y2=read();//printf("------
    ");
     98     }
     99     memset(tong,0,sizeof(tong));
    100     sort(e+1,e+q+1,cmp);
    101     for(int i=e[1].x1;i<=e[1].x2;++i){
    102         for(int j=e[1].y1;j<=e[1].y2;++j){
    103             ans-=tong[a[i][j]]*tong[a[i][j]];
    104             tong[a[i][j]]++;
    105             ans+=tong[a[i][j]]*tong[a[i][j]];
    106         }
    107     }
    108     l_x=e[1].x1;r_x=e[1].x2;l_y=e[1].y1;r_y=e[1].y2;e[1].ans=ans;
    109     for(int i=2;i<=q;++i){
    110         work_x(i);work_y(i);
    111         e[i].ans=ans;
    112     }
    113     sort(e+1,e+q+1,cmp1);
    114     for(int i=1;i<=q;++i){
    115         printf("%lld
    ",e[i].ans);
    116     }
    117 }
    View Code

    T3 联盟

    树上直径的好题,改了一个晚上+两节自习

    首先关于树上直径有个性质:

        距离所有点的最远距离最小的点是直径的中点

    那么这题拆的边肯定是直径上的边啦(想起了一道叫影子的题)

    但是我们需要求出两个联通块的直径,但是好像我们只会n^2处理.......

    但是我们发现假如我们断的边不是直径上的边那么断开后一个联通块的直径一定是原直径

    我们可以将直径拎直,然后以两个端点DP,求出了两个数组,分别表示两个联通块的子树的直径,

    设断开的联通块直径分别为L1,L2

    对于直径边,新连的直径一定是L1,L2,(L1/2(向上取整)+L2/2(向上取整))+1,的最大值

    所以直接判断,然后最后随便找出两个断点,找出新连的边即可

    (没有处理多直径的情况,不会.....)

    然后还有很多细节,非常****

    注意操作3中选的节点一定是直径上的点,而不是BFS中dis==len/2的点,画画图会发现,非直径上的点是不成立的

      1 #include<bits/stdc++.h>
      2 #define int long long
      3 #define MAXN 510000
      4 using namespace std;
      5 int head[MAXN],tot=0;
      6 int read(){
      7     int f=1;int x=0;char cc=getchar();
      8     while(cc<'0'||cc>'9'){cc=getchar();}
      9     while(cc>='0'&&cc<='9'){x=(x<<1)+(x<<3)+(cc^48);cc=getchar();}
     10     return x*f;
     11 }
     12 struct node{int to,n;}e[MAXN*2];int uu[MAXN],vv[MAXN];
     13 void add(int u,int v){e[++tot].to=v;e[tot].n=head[u];head[u]=tot;}
     14 int maxn,dis[MAXN];
     15 int pre[MAXN];
     16 int vis[MAXN];
     17 int n;
     18 int l1[MAXN],l2[MAXN];int loop[MAXN];
     19 int root1,root2;
     20 void DP(int x,int fa,int me){
     21      for(int i=head[x];i;i=e[i].n){
     22          int to=e[i].to;
     23          if(to==fa)continue;
     24          DP(to,x,me);
     25          maxn=max(maxn,dis[x]+dis[to]+1);
     26          loop[x]=max(loop[x],dis[x]+dis[to]+1);
     27          if(me==1){l1[x]=max(l1[x],dis[x]+dis[to]+1);l1[x]=max(l1[x],loop[to]);loop[x]=max(loop[x],l1[x]);}
     28          else     {l2[x]=max(l2[x],dis[x]+dis[to]+1);l2[x]=max(l2[x],loop[to]);loop[x]=max(loop[x],l2[x]);}
     29          dis[x]=max(dis[x],dis[to]+1);        
     30      }
     31 }
     32 queue<int>q;
     33 vector<int>v;
     34 int rt[MAXN];int len=0;int me_root[3];int biao_x,biao_y;
     35 void BFS(int x,int me){
     36      memset(dis,0,sizeof(dis));
     37      memset(pre,0,sizeof(pre));     
     38      memset(vis,0,sizeof(vis));
     39      while(!q.empty())q.pop();
     40      dis[x]=0;vis[x]=1;q.push(x);
     41      while(!q.empty()){
     42            int top=q.front();q.pop();
     43            for(int i=head[top];i;i=e[i].n){
     44                int to=e[i].to;
     45                if(vis[to]==1)continue;
     46                if(top==biao_x&&to==biao_y)continue;
     47                if(to==biao_x&&top==biao_y)continue;
     48                vis[to]=1;dis[to]=dis[top]+1;pre[to]=top;
     49                q.push(to);
     50            }
     51      }
     52      int maxn=0;int maxn_id=x;          
     53      for(int i=1;i<=n;++i){
     54          if(dis[i]>maxn){
     55             maxn=dis[i];maxn_id=i;
     56          }
     57      }
     58      len=maxn;
     59      if(me==1){root1=maxn_id;}
     60      else if(me==2){
     61           root2=maxn_id;v.push_back(maxn_id);rt[maxn_id]=1;len=maxn;
     62           while(maxn_id!=x){
     63                 maxn_id=pre[maxn_id];
     64                 v.push_back(maxn_id);
     65                 rt[maxn_id]=1;
     66           }
     67      }
     68      else if(me==3){
     69           if(len==0){me_root[++me_root[0]]=x; return ;}
     70           for(int kx=maxn_id;kx!=0;kx=pre[kx]){
     71               int i=kx;
     72               if(len%2==0){
     73                  if(dis[i]==len/2){
     74                     me_root[++me_root[0]]=i;
     75                     break;
     76                  }
     77               }
     78               else{
     79                  if(dis[i]==((len-1)/2)+1){
     80                     me_root[++me_root[0]]=i;
     81                     break;
     82                  }
     83               }
     84           }
     85      }
     86 }
     87 map<pair<int,int>,int>h;
     88 int ans1=0;int anss=0x7ffffffff;
     89 int ans[MAXN];int toot[3];
     90 signed main(){
     91      n=read();
     92      for(int i=1;i<=n-1;++i){
     93          int u,v;
     94          u=read();v=read();
     95          uu[i]=u;vv[i]=v;
     96          h[make_pair(uu[i],vv[i])]=i;
     97          h[make_pair(vv[i],uu[i])]=i;
     98          add(u,v);add(v,u);
     99      }
    100      BFS(1,1);
    101      biao_x=0;biao_y=0;
    102      BFS(root1,2);      
    103      maxn=0;memset(dis,0,sizeof(dis));memset(loop,0,sizeof(loop));
    104      DP(root2,0,2);     
    105      maxn=0;memset(dis,0,sizeof(dis));memset(loop,0,sizeof(loop));
    106      DP(root1,0,1);
    107      for(int i=0;i<v.size()-1;++i){//从root2开始
    108          int mex=v[i];int mey=v[i+1];
    109          int mm1=l2[mey];
    110          int mm0=l1[mex];
    111          int means=0;
    112          means=max(mm1,mm0);
    113          if(mm1%2==0&&mm1!=0){mm1/=2;}else if(mm1!=0) {mm1++,mm1/=2;}
    114          if(mm0%2==0&&mm0!=0){mm0/=2;}else if(mm0!=0) {mm0++,mm0/=2;}     
    115          means=max(means,mm1+mm0+1);
    116          if(means<anss){ans[0]=0;ans[++ans[0]]=h[make_pair(mex,mey)];toot[0]=mex;toot[1]=mey;}
    117          else if(means==anss){ans[++ans[0]]=h[make_pair(mex,mey)];toot[0]=mex;toot[1]=mey;}         
    118          anss=min(anss,means);
    119      }
    120      for(int i=1;i<=n-1;++i){
    121          int mex=uu[i];int mey=vv[i];int mm0,mm1,means;
    122          if(rt[mex]&&rt[mey])continue;
    123          mm1=min(l1[mex],l1[mey]);mm0=len;
    124          means=max(mm1,mm0);
    125          if(mm1%2==0&&mm1!=0){mm1/=2;}else if(mm1!=0) {mm1++,mm1/=2;}
    126          if(mm0%2==0&&mm0!=0){mm0/=2;}else if(mm0!=0){mm0++,mm0/=2;}     
    127          means=max(means,mm1+mm0+1);
    128          if(means<anss){ans[0]=0;ans[++ans[0]]=h[make_pair(mex,mey)];toot[0]=mex;toot[1]=mey;}
    129          else if(means==anss){ans[++ans[0]]=h[make_pair(mex,mey)];}         
    130          anss=min(anss,means);         
    131      }
    132      sort(ans+1,ans+ans[0]+1);
    133      printf("%lld
    ",anss);
    134      printf("%lld ",ans[0]);
    135      for(int i=1;i<=ans[0];++i){
    136          printf("%lld ",ans[i]);
    137      }
    138      cout<<endl;     
    139      biao_x=toot[0];biao_y=toot[1];
    140      BFS(toot[0],1);
    141      BFS(root1,3);
    142      biao_x=toot[0];biao_y=toot[1];
    143      BFS(toot[1],1);
    144      BFS(root1,3);
    145      printf("%lld %lld %lld %lld
    ",toot[0],toot[1],me_root[1],me_root[2]);     
    146 }
    View Code
  • 相关阅读:
    剑指 Offer 18. 删除链表的节点
    剑指 Offer 15. 二进制中1的个数
    剑指 Offer 11. 旋转数组的最小数字
    剑指 Offer 56
    剑指 Offer 10- II. 青蛙跳台阶问题
    剑指 Offer 10- I. 斐波那契数列
    剑指 Offer 09. 用两个栈实现队列
    剑指 Offer 06. 从尾到头打印链表
    C++ 异常机制
    读《大数据——互联网大规模数据挖掘与分布式处理》
  • 原文地址:https://www.cnblogs.com/Wwb123/p/11577650.html
Copyright © 2011-2022 走看看