牛客CSP-S提高组赛前集训营3
A 货物收集
显然是一个二分答案的题。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define dbg(x) cerr << #x << " = " << x <<endl
#define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=1e6+,INF=0x3f3f3f3f;
int val[N];
int n,L,R,w;
struct thxorz{
int head[N],nxt[N<<],to[N<<],w[N<<],tot;
inline void add(int x,int y,int z){
to[++tot]=y,nxt[tot]=head[x],head[x]=tot,w[tot]=z;
to[++tot]=x,nxt[tot]=head[y],head[y]=tot,w[tot]=z;
}
}G;
#define y G.to[j]
inline int dfs(int mid,int x,int fa){
int ret=val[x];
for(register int j=G.head[x];j;j=G.nxt[j])if(y^fa&&G.w[j]<=mid)ret+=dfs(mid,y,x);
return ret;
}
#undef y
int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
read(n),read(w);L=INF;
for(register int i=;i<=n;++i)read(val[i]);
for(register int i=,x,y,z;i<n;++i)read(x),read(y),read(z),G.add(x,y,z),MIN(L,z),MAX(R,z);
int mid;
while(L<R){
mid=L+R>>;
if(dfs(mid,,)>=w)R=mid;
else L=mid+;
}
printf("%d\n",L);
return ;
}
B 货物分组
写出一个裸的DP方程。$O(n^3)$.
$f_{i,k}=\min\{f_{j,k-1}+k(sum_i-sum_{j-1})+\max_{j+1\sim i}-\min_{j+1\sim i}\}$
然后因为这个涉及和$k$相关的乘积项,为了简化$k$这一维的状态,采用费用预算的思想,将后面所有组都提前加上一次他们总和。
所以去掉$k$这一维,$O(n^2)$。
$f_i=\min\{f_j-sum_j+\max_{j+1\sim i}-\min_{j+1\sim i}\}$
然后要考虑优化。我DP优化学傻掉了。`````
发现max和min实际上每次都是一个元素控制他前面的一段区间。这个可以用单调栈求出,然后max若干段区间和min若干段区间,每段最值都相同。那么,把方程前两项压入线段树,然后后面的max和min通过修改来完成:每次更新区间的时候,把弹栈的若干区间里的状态去掉他们原来的最值,加上新加入栈的最值。这个就是个区间修改,然后线段树维护最小值,每次转移区间查询即可。$O(n\log n)$。
这里用了标记永久化,实际上是学hkk的,可以发现常数小一些,核心在于在某节点内部的区间上传信息时都要加上自己打的标记。
WA*1:线段树里下标表示对应的状态前两项,单调栈里是最值。。搞反了导致line54~line57出错。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define mst(x) memset(x,0,sizeof x)
#define dbg(x) cerr << #x << " = " << x <<endl
#define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=1e5+;
const ll INF=1ll<<;
struct segment_tree{
ll minv[N<<],atag[N<<];
#define lc i<<1
#define rc i<<1|1
// segment_tree(){memset(minv,0x3f,sizeof minv);}
void update_add(int i,int L,int R,int ql,int qr,ll val){
if(ql<=L&&qr>=R)return minv[i]+=val,atag[i]+=val,void();
int mid=L+R>>;
if(ql<=mid)update_add(lc,L,mid,ql,qr,val);
if(qr>mid)update_add(rc,mid+,R,ql,qr,val);
minv[i]=_min(minv[lc],minv[rc])+atag[i];
}
ll query_min(int i,int L,int R,int ql,int qr){
if(ql<=L&&qr>=R)return minv[i];
int mid=L+R>>;ll ret=INF;
if(ql<=mid)MIN(ret,query_min(lc,L,mid,ql,qr));
if(qr>mid)MIN(ret,query_min(rc,mid+,R,ql,qr));
return ret+atag[i];
}//pay attention to the permanent tag...
}T;
int stkmin[N],stkmax[N],A[N],top1,top2;
ll s[N],f[N];
int n,w,lb; int main(){//freopen("2.in","r",stdin);//freopen("test.ans","w",stdout);
read(n),read(w);stkmin[]=stkmax[]=-;
for(register int i=;i<=n;++i)s[i]=s[i-]+read(A[i]);
for(register int i=;i<=n;++i){//dbg(i);
T.update_add(,,n-,i-,i-,f[i-]+s[n]-s[i-]);
while(top1&&A[stkmin[top1]]>=A[i])T.update_add(,,n-,stkmin[top1-],stkmin[top1]-,A[stkmin[top1]]),--top1;
T.update_add(,,n-,stkmin[top1],i-,-A[i]),stkmin[++top1]=i;//dbg(top1);
while(top2&&A[stkmax[top2]]<=A[i])T.update_add(,,n-,stkmax[top2-],stkmax[top2]-,-A[stkmax[top2]]),--top2;
T.update_add(,,n-,stkmax[top2],i-,A[i]),stkmax[++top2]=i;//dbg(top2);
while(s[i]-s[lb]>w)++lb;
f[i]=T.query_min(,,n-,lb,i-);
}
printf("%lld\n",f[n]);
return ;
}
C 地形计算
复杂度计算非常神仙的一个题。其实这题复杂度我也不会算,以下为口胡
顺便学习了一下三元环和四元环的计数。连接1(有复杂度证明),连接2(好像做法不对?),连接3
三元环的话主要就是因为定了向,好处有二:一是每个环只会被计一次,二是复杂度可以利用这个度数大小关系证出来是根号的。
四元环的话,类似。原来的三元环是度数大的向度数小的走,现在为了走四元环保证复杂度,只能每次走深度为2的路(相当于就走了一次三元环),然后所有终点相同、深度为二的里做统计计算。
不过并不是边直接从度数大的走向小的,这样会有四元环被漏计,为了保证每个环被算一次且仅一次,改变走边方法,枚举每一个起点$x$,然后枚举走到的$y$,要求度数$x>y$(相等时按编号),然后再从$y$开始遍历走到的$z$,要求度数也有$z<x$,这样,每个环只会被度数最大的那个点统计到。同时还可以保证复杂度:假设现在$y$度数小于$\sqrt{M}$,则$x$遍历图中每条边,到达的点向外拓展,复杂度$O(M\sqrt{M})$。若$y$度数大于$\sqrt{M}$,则利用度数传递性,$x$度数也应当大于根号,所以得知总的这样的$x$不会超过根号个,所以每一个$y$有不超过根号个入点$x$进来,对于每一个点$y$贡献复杂度$O(\sqrt{M}outdegree_y)$,又因为$\sum outdegree_y\le m$,所以总体也是$O(M\sqrt{M})$的。证毕。其实这也是三元环复杂度的证明方法。
然后这题就算权值就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define mst(x) memset(x,0,sizeof x)
#define dbg(x) cerr << #x << " = " << x <<endl
#define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=1e5+,P=1e9+;
struct thxorz{
int head[N],nxt[N<<],to[N<<],tot;
inline void add(int x,int y){
to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
}
}G;
int val[N],deg[N],vis[N],sum[N],cnt[N];
int n,m,ans;
inline void add(int&a,int b){((a+=b)>=P)&&(a-=P);}
inline int mod(int a){return a>=P?a-P:a;} int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
read(n),read(m);
for(register int i=;i<=n;++i)read(val[i]);
for(register int i=,x,y;i<=m;++i)read(x),read(y),G.add(x,y),++deg[x],++deg[y];
#define y G.to[i]
#define z G.to[j]
for(register int x=;x<=n;++x){
for(register int i=G.head[x];i;i=G.nxt[i])if(deg[y]<deg[x]||deg[x]==deg[y]&&y<x){
for(register int j=G.head[y];j;j=G.nxt[j])if(deg[z]<deg[x]||deg[z]==deg[x]&&z<x){
if(vis[z]^x)vis[z]=x,cnt[z]=,sum[z]=val[y];
else add(ans,mod(cnt[z]*1ll*(val[x]+val[z]+0ll+val[y])%P+sum[z])),++cnt[z],add(sum[z],val[y]);
}
}
}
printf("%d\n",ans);
return ;
}
牛客CSP-S提高组赛前集训营3的更多相关文章
- 牛客网CSP-S提高组赛前集训营Round4
牛客网CSP-S提高组赛前集训营 标签(空格分隔): 题解 算法 模拟赛 题目 描述 做法 \(BSOJ6377\) 求由\(n\)长度的数组复制\(k\)次的数组里每个连续子序列出现数字种类的和 对 ...
- 牛客CSP-S提高组赛前集训营1
牛客CSP-S提高组赛前集训营1 比赛链接 官方题解 before:T1观察+结论题,T2树形Dp,可以换根或up&down,T3正解妙,转化为图上问题.题目质量不错,但数据太水了~. A-仓 ...
- 牛客CSP-S提高组赛前集训营3 赛后总结
货物收集 二分答案.复杂度\(O(n\log n)\). 货物分组 用费用提前计算的思想,考虑用一个新的箱子来装货物会发生什么. 显然费用会加上后面的所有货物的总重. \(60\)分的\(O(n^2) ...
- 牛客CSP-S提高组赛前集训营2 ———— 2019.10.31
比赛链接 期望得分:100+20+20 实际得分:40+20+30 awa cccc T1 :基于贪心的思路,然后开始爆搜(雾 那必然是会死的,好吧他就是死了 #include<iostrea ...
- 牛客CSP-S提高组赛前集训营1———2019.10.29 18:30 至 22:00
期望得分:100+0+10 实际得分:40+0+0 考炸了... T1:题目链接 究竟为什么会这样,,, 仔细研读我的丑代码 发现... 枯辽.... #include<cstdio> # ...
- 牛客CSP-S提高组赛前集训营2 T2沙漠点列
原题链接 算法不难,比赛的时候就和cyc大佬一起yy了正解,不过因为交的时候比较急(要回寝室惹),我有两数组开错大小直接爆到50,cyc大佬则只把文件输入关了一半,直接爆零(╯ ̄Д ̄)╯┻━┻ 要尽量 ...
- 20191029 牛客CSP-S提高组赛前集训营1
前一个小时看这几道题感觉要爆零 A. 仓鼠的石子游戏 分析一下发现a[i]>1a[i]>1a[i]>1时后先手必输,a[i]=1a[i]=1a[i]=1时先手必赢 然后直接看1的个数 ...
- 牛客CSP-S提高组赛前集训营4 赛后总结
复读数组 分成 3 种区间算答案: 一个块内的区间 两个块交界处,长度小于块长的区间 长度不小于块长的区间 对于第三种区间,容易发现每个区间的权值一样,只需要算出个数即可. 对于前两种空间,我的思路是 ...
- 牛客CSP-S提高组赛前集训营5 赛后总结
A.无形的博弈 心理题. 答案为\(2^n\),可感性理解结论的正确性. #include<bits/stdc++.h> #define LL long long const LL Mod ...
随机推荐
- kindeditor 在JSP 中上传文件的配置
1.将kindeditor,jsp,lib目录下的jar文件放到工程的lib目录下 2.将admin-login.jsp,upload_json.jsp,复制到admin的files目录下 3.复制以 ...
- windows上OpenSSH服务安装及启动
一.windows安装OpenSSH 1,下载openSSH windows版 GitHub下载链接 我安装的是64位版本 OpenSSH-Win64.zip 2,解压到C:\Program File ...
- Mysql错误--Table 'mysql.servers' doesn't exist.
问题: 今天在初始化数据库的时候,在配置文件里加了"--skip grant tables",登陆进去之后,发现无法修改root密码,报这个错误. Table 'mysql.s ...
- ZUI(BootStrap)使用vue动态插入HTMl所创建的data-toggle事件初始化方法
用ZUI的图片浏览:lightbox 写静态html的时候是有预览效果的,使用了vue动态加载就没有效果了, 网上的说法是动态生成的没有激活事件:ZUI(BootStrap)动态插入HTMl所创建的d ...
- [转帖]Linux环境变量设置方法总结 PATH、LD_LIBRARY_PATH
Linux环境变量设置方法总结 PATH.LD_LIBRARY_PATH 2018年01月17日 21:10:26 晨至曦 阅读数 7548 https://blog.csdn.net/qq_1900 ...
- Nginx04---编译安装
原文:https://www.cnblogs.com/zhang-shijie/p/5294162.html 一:基介绍 官网地址www.nginx.org,nginx是由1994年毕业于俄罗斯国立莫 ...
- django fields lookup methods(lookup类型)
__exact 精确等于 like 'aaa' __iexact 精确等于 忽略大小写 ilike 'aaa' __contains 包含 like '%aaa%' __ic ...
- rownum伪行号-排行榜-分页
rownum伪行号-排行榜-分页 1.rownum 是oracle数据库特有的一个特性,它针对每一个查询(包括子查询),都会生成一个rownum用于对该次查询进行编号 2.每个rownum只针对当前s ...
- 树链剖分 树剖求lca 学习笔记
树链剖分 顾名思义,就是把一课时分成若干条链,使得它可以用数据结构(例如线段树)来维护 一些定义: 重儿子:子树最大的儿子 轻儿子:除了重儿子以外的儿子 重边:父节点与重儿子组成的边 轻边:除重边以外 ...
- PHP无限极菜单
权限表结构 CREATE TABLE `blog_auth` ( `id` ) unsigned NOT NULL AUTO_INCREMENT COMMENT '序号', `pid` ) NOT N ...