zoukankan      html  css  js  c++  java
  • 牛客CSP-S提高组赛前集训营3

    A 货物收集

    显然是一个二分答案的题。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define dbg(x) cerr << #x << " = " << x <<endl
     8 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
     9 using namespace std;
    10 typedef long long ll;
    11 typedef double db;
    12 typedef pair<int,int> pii;
    13 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    14 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    15 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    16 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    17 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    18 template<typename T>inline T read(T&x){
    19     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    20     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    21 }
    22 const int N=1e6+7,INF=0x3f3f3f3f;
    23 int val[N];
    24 int n,L,R,w;
    25 struct thxorz{
    26     int head[N],nxt[N<<1],to[N<<1],w[N<<1],tot;
    27     inline void add(int x,int y,int z){
    28         to[++tot]=y,nxt[tot]=head[x],head[x]=tot,w[tot]=z;
    29         to[++tot]=x,nxt[tot]=head[y],head[y]=tot,w[tot]=z;
    30     }
    31 }G;
    32 #define y G.to[j]
    33 inline int dfs(int mid,int x,int fa){
    34     int ret=val[x];
    35     for(register int j=G.head[x];j;j=G.nxt[j])if(y^fa&&G.w[j]<=mid)ret+=dfs(mid,y,x);
    36     return ret;
    37 }
    38 #undef y
    39 int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
    40     read(n),read(w);L=INF;
    41     for(register int i=2;i<=n;++i)read(val[i]);
    42     for(register int i=1,x,y,z;i<n;++i)read(x),read(y),read(z),G.add(x,y,z),MIN(L,z),MAX(R,z);
    43     int mid;
    44     while(L<R){
    45         mid=L+R>>1;
    46         if(dfs(mid,1,0)>=w)R=mid;
    47         else L=mid+1;
    48     }
    49     printf("%d
    ",L);
    50     return 0;
    51 }
    View Code

    B 货物分组

    写出一个裸的DP方程。$O(n^3)$.

    $f_{i,k}=min{f_{j,k-1}+k(sum_i-sum_{j-1})+max_{j+1sim i}-min_{j+1sim i}}$

    然后因为这个涉及和$k$相关的乘积项,为了简化$k$这一维的状态,采用费用预算的思想,将后面所有组都提前加上一次他们总和。

    所以去掉$k$这一维,$O(n^2)$。

    $f_i=min{f_j-sum_j+max_{j+1sim i}-min_{j+1sim i}}$

    然后要考虑优化。我DP优化学傻掉了。`````

    发现max和min实际上每次都是一个元素控制他前面的一段区间。这个可以用单调栈求出,然后max若干段区间和min若干段区间,每段最值都相同。那么,把方程前两项压入线段树,然后后面的max和min通过修改来完成:每次更新区间的时候,把弹栈的若干区间里的状态去掉他们原来的最值,加上新加入栈的最值。这个就是个区间修改,然后线段树维护最小值,每次转移区间查询即可。$O(nlog n)$。

    这里用了标记永久化,实际上是学hkk的,可以发现常数小一些,核心在于在某节点内部的区间上传信息时都要加上自己打的标记。

    WA*1:线段树里下标表示对应的状态前两项,单调栈里是最值。。搞反了导致line54~line57出错。。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=1e5+7;
    24 const ll INF=1ll<<50;
    25 struct segment_tree{
    26     ll minv[N<<2],atag[N<<2];
    27     #define lc i<<1
    28     #define rc i<<1|1
    29 //    segment_tree(){memset(minv,0x3f,sizeof minv);}
    30     void update_add(int i,int L,int R,int ql,int qr,ll val){
    31         if(ql<=L&&qr>=R)return minv[i]+=val,atag[i]+=val,void();
    32         int mid=L+R>>1;
    33         if(ql<=mid)update_add(lc,L,mid,ql,qr,val);
    34         if(qr>mid)update_add(rc,mid+1,R,ql,qr,val);
    35         minv[i]=_min(minv[lc],minv[rc])+atag[i];
    36     }
    37     ll query_min(int i,int L,int R,int ql,int qr){
    38         if(ql<=L&&qr>=R)return minv[i];
    39         int mid=L+R>>1;ll ret=INF;
    40         if(ql<=mid)MIN(ret,query_min(lc,L,mid,ql,qr));
    41         if(qr>mid)MIN(ret,query_min(rc,mid+1,R,ql,qr));
    42         return ret+atag[i];
    43     }//pay attention to the permanent tag...
    44 }T;
    45 int stkmin[N],stkmax[N],A[N],top1,top2;
    46 ll s[N],f[N];
    47 int n,w,lb;
    48 
    49 int main(){//freopen("2.in","r",stdin);//freopen("test.ans","w",stdout);
    50     read(n),read(w);stkmin[0]=stkmax[0]=-1;
    51     for(register int i=1;i<=n;++i)s[i]=s[i-1]+read(A[i]);
    52     for(register int i=1;i<=n;++i){//dbg(i);
    53         T.update_add(1,0,n-1,i-1,i-1,f[i-1]+s[n]-s[i-1]);
    54         while(top1&&A[stkmin[top1]]>=A[i])T.update_add(1,0,n-1,stkmin[top1-1],stkmin[top1]-1,A[stkmin[top1]]),--top1;
    55         T.update_add(1,0,n-1,stkmin[top1],i-1,-A[i]),stkmin[++top1]=i;//dbg(top1);
    56         while(top2&&A[stkmax[top2]]<=A[i])T.update_add(1,0,n-1,stkmax[top2-1],stkmax[top2]-1,-A[stkmax[top2]]),--top2;
    57         T.update_add(1,0,n-1,stkmax[top2],i-1,A[i]),stkmax[++top2]=i;//dbg(top2);
    58         while(s[i]-s[lb]>w)++lb;
    59         f[i]=T.query_min(1,0,n-1,lb,i-1);
    60     }
    61     printf("%lld
    ",f[n]);
    62     return 0;
    63 }
    View Code

    C 地形计算

    复杂度计算非常神仙的一个题。其实这题复杂度我也不会算,以下为口胡

    顺便学习了一下三元环和四元环的计数。连接1(有复杂度证明)连接2(好像做法不对?)连接3

    三元环的话主要就是因为定了向,好处有二:一是每个环只会被计一次,二是复杂度可以利用这个度数大小关系证出来是根号的。

    四元环的话,类似。原来的三元环是度数大的向度数小的走,现在为了走四元环保证复杂度,只能每次走深度为2的路(相当于就走了一次三元环),然后所有终点相同、深度为二的里做统计计算。

    不过并不是边直接从度数大的走向小的,这样会有四元环被漏计,为了保证每个环被算一次且仅一次,改变走边方法,枚举每一个起点$x$,然后枚举走到的$y$,要求度数$x>y$(相等时按编号),然后再从$y$开始遍历走到的$z$,要求度数也有$z<x$,这样,每个环只会被度数最大的那个点统计到。同时还可以保证复杂度:假设现在$y$度数小于$sqrt{M}$,则$x$遍历图中每条边,到达的点向外拓展,复杂度$O(Msqrt{M})$。若$y$度数大于$sqrt{M}$,则利用度数传递性,$x$度数也应当大于根号,所以得知总的这样的$x$不会超过根号个,所以每一个$y$有不超过根号个入点$x$进来,对于每一个点$y$贡献复杂度$O(sqrt{M}outdegree_y)$,又因为$sum outdegree_yle m$,所以总体也是$O(Msqrt{M})$的。证毕。其实这也是三元环复杂度的证明方法。

    然后这题就算权值就好了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=1e5+7,P=1e9+7;
    24 struct thxorz{
    25     int head[N],nxt[N<<1],to[N<<1],tot;
    26     inline void add(int x,int y){
    27         to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
    28         to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
    29     }
    30 }G;
    31 int val[N],deg[N],vis[N],sum[N],cnt[N];
    32 int n,m,ans;
    33 inline void add(int&a,int b){((a+=b)>=P)&&(a-=P);}
    34 inline int mod(int a){return a>=P?a-P:a;}
    35 
    36 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    37     read(n),read(m);
    38     for(register int i=1;i<=n;++i)read(val[i]);
    39     for(register int i=1,x,y;i<=m;++i)read(x),read(y),G.add(x,y),++deg[x],++deg[y];
    40     #define y G.to[i]
    41     #define z G.to[j]
    42     for(register int x=1;x<=n;++x){
    43         for(register int i=G.head[x];i;i=G.nxt[i])if(deg[y]<deg[x]||deg[x]==deg[y]&&y<x){
    44             for(register int j=G.head[y];j;j=G.nxt[j])if(deg[z]<deg[x]||deg[z]==deg[x]&&z<x){
    45                 if(vis[z]^x)vis[z]=x,cnt[z]=1,sum[z]=val[y];
    46                 else add(ans,mod(cnt[z]*1ll*(val[x]+val[z]+0ll+val[y])%P+sum[z])),++cnt[z],add(sum[z],val[y]);
    47             }
    48         }
    49     }
    50     printf("%d
    ",ans);
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    Day08_固化命令、grep、sed及awk命令
    Day07_网络管理、SSH、shell及元字符
    Day06_nginx及反向代理、共享存储nfs
    安装Apache所踩的的坑
    使用JS制作小游戏贪吃蛇
    清除浮动的几种方式
    纯CSS3图片反转
    在JAVASCRIPT中,为什么document.getElementById不可以再全局(函数外)使用?
    关于钉钉开发,心得
    javascript计算两个时间差
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11799539.html
Copyright © 2011-2022 走看看