PKUSC 模拟赛 day1 上午总结

时间:2022-12-19 19:13:05

思考了一下第二题,觉得有无数种乱搞做法

类似什么bitset压位,MCS染色之类奇怪的做法

然而都是玄学正确性或者玄学复杂度

先放题解把

第一题显然具有单调性,二分就可以啦

O(nlogn),貌似输出要求去尾QAQ

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define eps 1e-3
using namespace std; typedef long long LL;
const int maxn=100010;
int n,k;
double a[maxn];
double mx,mn; LL check(double k){
LL sum=0;
for(int i=1;i<=n;++i){
sum+=(LL)(a[i]/k);
}return sum;
} int main(){
scanf("%d%d",&n,&k);
mn=1e12;mx=-1e12;
for(int i=1;i<=n;++i){
scanf("%lf",&a[i]);
mx=max(mx,a[i]);
mn=min(mn,a[i]);
}
double L=mx/k,R=mx;
while(R-L>eps){
double mid=(L+R)/2.0;
if(check(mid)<k)R=mid;
else L=mid;
}printf("%.2lf\n",fabs(L-4*eps));
return 0;
}

第二题略过,又臭又长的题面,比赛的时候看都没有看

第三题显然我们枚举可选区间的右端点,寻找满足条件的最远的左端点

ans=sigma(Ri-Li+1)

然后判断是否合法就是查询区间最大值和区间最小值,直接线段树或者ST表可以做到O(logn)的查询

如果我们二分这个左端点,显然时间复杂度O(nlog^2n),这是会T的

我们很容易发现随着右端点的递增,左端点也是递增的,维护一个单调指针即可

时间复杂度O(nlogn)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std; typedef long long LL;
const int maxn=100010;
int T,n,k;
int a[maxn];
int mx[maxn<<2];
int mn[maxn<<2];
LL ans;
void read(int &num){
num=0;char ch=getchar();
while(ch<'!')ch=getchar();
while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
}
void build(int o,int L,int R){
if(L==R){mn[o]=mx[o]=a[L];return;}
int mid=(L+R)>>1;
build(o<<1,L,mid);
build(o<<1|1,mid+1,R);
mx[o]=max(mx[o<<1|1],mx[o<<1]);
mn[o]=min(mn[o<<1|1],mn[o<<1]);
}
int ask_max(int o,int L,int R,int x,int y){
if(L>=x&&R<=y)return mx[o];
int mid=(L+R)>>1;
if(y<=mid)return ask_max(o<<1,L,mid,x,y);
else if(x>mid)return ask_max(o<<1|1,mid+1,R,x,y);
else return max(ask_max(o<<1,L,mid,x,y),ask_max(o<<1|1,mid+1,R,x,y));
}
int ask_min(int o,int L,int R,int x,int y){
if(L>=x&&R<=y)return mn[o];
int mid=(L+R)>>1;
if(y<=mid)return ask_min(o<<1,L,mid,x,y);
else if(x>mid)return ask_min(o<<1|1,mid+1,R,x,y);
else return min(ask_min(o<<1,L,mid,x,y),ask_min(o<<1|1,mid+1,R,x,y));
} int main(){
read(T);
while(T--){
read(n);read(k);
for(int i=1;i<=n;++i)read(a[i]);
build(1,1,n);int pos=1;
ans=0;
for(int i=1;i<=n;++i){
while(pos<=i&&ask_max(1,1,n,pos,i)-ask_min(1,1,n,pos,i)>=k)pos++;
ans=ans+i-pos+1;
}printf("%lld\n",ans);
}return 0;
}

第四题弱化一下问题,如果不是链是边显然我们一遍树形DP就可以搞定了

扩展一下树形DP的做法之后我们发现当我们选择一条链之后这棵树被分解成若干子树,每个子树都是独立的

还是可以做树形DP的,关键是快速计算每种方案的价值

我们定义s2表示每个点儿子的DP值的和,s1表示自己的DP值的和

那么选择一条链的价值就是这条链上s2的和减去s1的和+这条链的收益,这是容易用树链剖分或者LCT维护的

DP的时候转移两种情况,当前点被链覆盖和不被链覆盖,随意搞一搞就可以啦

考试的时候比较傻,能用树状数组不用写线段树,能用树剖求LCA还要写倍增,最后码了20多分钟才码完,整整4K+ QAQ

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std; const int maxn=100010;
int T,n,m,u,v,now;
int h[maxn],cnt=0;
struct edge{
int to,next;
}G[maxn<<1];
struct Line{
int u,v,val,lca;
}c[maxn];
int ed[maxn],tot;
int fa[maxn],dep[maxn],w[maxn],son[maxn];
int pos[maxn],fp[maxn],top[maxn],sum;
int anc[maxn][20];
int s1[maxn<<2];
int s2[maxn<<2];
int dp[maxn]; bool cmp(const Line &A,const Line &B){
return ed[A.lca]<ed[B.lca];
}
void add(int x,int y){
++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;
}
void read(int &num){
num=0;char ch=getchar();
while(ch<'!')ch=getchar();
while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
}
void DFS(int u,int f){
fa[u]=f;w[u]=1;
for(int i=h[u];i;i=G[i].next){
int v=G[i].to;
if(v==f)continue;
dep[v]=dep[u]+1;
DFS(v,u);w[u]+=w[v];
if(w[son[u]]<w[v])son[u]=v;
}ed[u]=++tot;return;
}
void Get_pos(int u,int f){
top[u]=f;pos[u]=++sum;fp[sum]=u;
if(!son[u])return;
Get_pos(son[u],f);
for(int i=h[u];i;i=G[i].next){
int v=G[i].to;
if(v==fa[u]||v==son[u])continue;
Get_pos(v,v);
}return;
}
void pre_LCA(){
for(int i=1;i<=n;++i){
anc[i][0]=fa[i];
for(int j=1;(1<<j)<=n;++j)anc[i][j]=-1;
}
for(int j=1;(1<<j)<=n;++j){
for(int i=1;i<=n;++i){
if(anc[i][j-1]!=-1){
int a=anc[i][j-1];
anc[i][j]=anc[a][j-1];
}
}
}return;
}
int LCA(int p,int q){
if(dep[p]<dep[q])swap(p,q);
int log;
for(log=0;(1<<log)<=dep[p];++log);--log;
for(int i=log;i>=0;--i){
if(dep[p]-(1<<i)>=dep[q])p=anc[p][i];
}
if(p==q)return p;
for(int i=log;i>=0;--i){
if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){
p=anc[p][i];q=anc[q][i];
}
}return anc[p][0];
}
void UPD_s1(int o){s1[o]=s1[o<<1|1]+s1[o<<1];}
void UPD_s2(int o){s2[o]=s2[o<<1|1]+s2[o<<1];}
void build(int o,int L,int R){
if(L==R){s1[o]=s2[o]=0;return;}
int mid=(L+R)>>1;
build(o<<1,L,mid);
build(o<<1|1,mid+1,R);
UPD_s1(o);UPD_s2(o);
}
void modify_s1(int o,int L,int R,int p,int v){
if(L==R){s1[o]+=v;return;}
int mid=(L+R)>>1;
if(p<=mid)modify_s1(o<<1,L,mid,p,v);
else modify_s1(o<<1|1,mid+1,R,p,v);
UPD_s1(o);
}
void modify_s2(int o,int L,int R,int p,int v){
if(L==R){s2[o]+=v;return;}
int mid=(L+R)>>1;
if(p<=mid)modify_s2(o<<1,L,mid,p,v);
else modify_s2(o<<1|1,mid+1,R,p,v);
UPD_s2(o);
}
int ask(int o,int L,int R,int x,int y){
if(L>=x&&R<=y)return s2[o]-s1[o];
int mid=(L+R)>>1;
if(y<=mid)return ask(o<<1,L,mid,x,y);
else if(x>mid)return ask(o<<1|1,mid+1,R,x,y);
else return ask(o<<1,L,mid,x,y)+ask(o<<1|1,mid+1,R,x,y);
}
int ask_s2(int o,int L,int R,int p){
if(L==R)return s2[o];
int mid=(L+R)>>1;
if(p<=mid)return ask_s2(o<<1,L,mid,p);
else return ask_s2(o<<1|1,mid+1,R,p);
}
int ASK(int u,int v){
int sum=0;
while(top[u]!=top[v]){
sum+=ask(1,1,n,pos[top[u]],pos[u]);
u=fa[top[u]];
}sum+=ask(1,1,n,pos[v],pos[u]);
return sum;
}
void Get_DP(int u,int f){
for(int i=h[u];i;i=G[i].next){
int v=G[i].to;
if(v==f)continue;
Get_DP(v,u);
dp[u]+=dp[v];
}
while(now<=m&&c[now].lca==u){
int ans=c[now].val+ASK(c[now].u,c[now].lca)+ASK(c[now].v,c[now].lca);
ans=ans-ask_s2(1,1,n,pos[c[now].lca]);
dp[u]=max(dp[u],ans);now++;
}
modify_s1(1,1,n,pos[u],dp[u]);
if(fa[u]!=-1)modify_s2(1,1,n,pos[fa[u]],dp[u]);
}
int main(){
read(T);
while(T--){
read(n);read(m);
for(int i=1;i<=n;++i)h[i]=0;
cnt=0;
for(int i=1;i<=n;++i)son[i]=0;
for(int i=1;i<n;++i){
read(u);read(v);
add(u,v);add(v,u);
}tot=0;DFS(1,-1);
sum=0;Get_pos(1,-1);
pre_LCA();
for(int i=1;i<=m;++i){
read(c[i].u);read(c[i].v);read(c[i].val);
c[i].lca=LCA(c[i].u,c[i].v);
}
sort(c+1,c+m+1,cmp);now=1;
build(1,1,n);
for(int i=1;i<=n;++i)dp[i]=0;
Get_DP(1,-1);
printf("%d\n",dp[1]);
}return 0;
}

第五题显然L/(R-L+1)<=2015不是白给的

仔细分析发现这个区间在线段树上的深度不会很大,暴力搜索还原所有可能的区间就可以啦

貌似裸搜就能过啦

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std; typedef long long LL;
const LL oo=1LL<<62;
LL ans;
LL a,b;
void DFS(LL L,LL R,LL len,int dep){
if(L==0)ans=min(ans,R);
if(L<0)return;
if(R>ans)return;
if(dep==12)return;
DFS(L,R+len,len<<1,dep+1);
DFS(L-len,R,len<<1,dep+1);
DFS(L-len-1,R,len<<1|1,dep+1);
DFS(L,R+len-1,(len<<1)-1,dep+1);
} int main(){
while(scanf("%d%d",&a,&b)==2){
LL len=(b-a+1);
ans=oo;
DFS(a,b,len,0);
if(ans==oo)printf("-1\n");
else printf("%lld\n",ans);
}return 0;
}

第六题一眼题,HEOI2016的题目+一个输出字典序最小的方案

然而看到题目的时候离比赛结束只有25分钟了,疯狂码码码

交上去之后不停得RE,然后开始写对拍,写暴力

我居然在25分钟之内写完了正解,数据生成器和暴力!

人的潜能真是无穷的啊,最后发现自己忘记离散化了QAQ

最后还剩3分钟的时候交上去A掉了

我们考虑DP,把可转移的条件写出来发现是三维偏序,直接上CDQ就可以啦

之后要求字典序最小我们不妨采用从后往前DP的形式就很容易确定啦

然后树状数组多维护一个pos之后就可以了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std; const int maxn=100010;
int n,cnt;
int pre[maxn];
int dp[maxn];
int tmp[maxn];
struct Num{
int a,b,id;
}c[maxn];
int tim=0;
struct BIT{
int t,v,p;
}t[maxn]; bool cmpa(const Num &A,const Num &B){
return A.a<B.a;
}
bool cmpb(const Num &A,const Num &B){
if(A.b==B.b)return A.id>B.id;
return A.b>B.b;
}
bool cmpid(const Num &A,const Num &B){
return A.id<B.id;
}
void read(int &num){
num=0;char ch=getchar();
while(ch<'!')ch=getchar();
while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
}
int lowbit(int x){return x&(-x);}
void UPD(int x,int pos,int v){
for(int i=x;i<=n;i+=lowbit(i)){
if(t[i].t!=tim)t[i].t=tim,t[i].v=0,t[i].p=0;
if(v>t[i].v||(v==t[i].v&&pos<t[i].p)){
t[i].v=v;t[i].p=pos;
}
}return;
}
pair<int,int> ask(int x){
int sum=0,p=0;
for(int i=x;i>=1;i-=lowbit(i)){
if(t[i].t==tim){
if(t[i].v>sum||(t[i].v==sum&&t[i].p<p)){
sum=t[i].v;
p=t[i].p;
}
}
}return make_pair(sum,p);
}
void Solve(int L,int R){
if(L>=R)return;
int mid=(L+R)>>1;
Solve(mid+1,R);
sort(c+L,c+R+1,cmpb);
tim++;
for(int i=L;i<=R;++i){
if(c[i].id>mid)UPD(c[i].a,c[i].id,dp[c[i].id]);
else{
pair<int,int>now=ask(c[i].a);
if(now.first+1>dp[c[i].id]||(now.first+1==dp[c[i].id]&&now.second<pre[c[i].id])){
dp[c[i].id]=now.first+1;
pre[c[i].id]=now.second;
}
}
}
sort(c+L,c+R+1,cmpid);
Solve(L,mid);
}
void print(int k){
if(!k)return;
printf("%d",k);
if(!pre[k])printf("\n");
else{
printf(" ");
print(pre[k]);
}return;
} int main(){
while(scanf("%d",&n)==1){
tim++;
for(int i=1;i<=n;++i)read(c[i].a),c[i].id=i;
for(int i=1;i<=n;++i)read(c[i].b);
sort(c+1,c+n+1,cmpa);cnt=0;
for(int i=1;i<=n;++i)tmp[i]=c[i].a;
for(int i=1;i<=n;++i){
if(tmp[i]!=tmp[i-1])c[i].a=++cnt;
else c[i].a=cnt;
}
sort(c+1,c+n+1,cmpid);
for(int i=1;i<=n;++i)dp[i]=1,pre[i]=0;
Solve(1,n);
int ans=0,k=0;
for(int i=1;i<=n;++i){
ans=max(ans,dp[i]);
}printf("%d\n",ans);
for(int i=1;i<=n;++i){
if(ans==dp[i]){k=i;break;}
}
print(k);
}return 0;
}

感觉今天上午属于超常发挥,而且在cojs上出题的功效也发挥出来了,上午的五道题我有三道题都写完了一套(正解,暴力,数据生成器)

出题对码力的提升是不可小觑的

考试时较好的地方:

1、直接跳过了第二题(事实证明结束的时候也没有人A掉第二题)

2、第四题没有畏惧代码量,直接强行4K+在半个小时之内就搞定了

3、第五题的乱搞方法非常值得以后比赛借鉴(注意到了题目信息)

考试时不太好的地方:

1、第一题没有仔细读题,导致并不知道要求去尾输出

2、第四题的思维没有优化,导致代码量过大

3、第六题写的时候心中有些紧张了,导致忘记了离散化,差点就没有A掉

PKUSC 模拟赛 day1 上午总结的更多相关文章

  1. PKUSC 模拟赛 day1 下午总结

    下午到了机房之后又困又饿,还要被强行摁着看英文题,简直差评 第一题是NOIP模拟赛的原题,随便模拟就好啦 本人模拟功力太渣不小心打错了个变量,居然调了40多分钟QAQ #include<cstd ...

  2. PKUSC 模拟赛 day2 上午总结

    今天上午考得不是很好,主要还是自己太弱QAQ 开场第一题给的图和题意不符,搞了半天才知道原来是走日字形的 然后BFS即可 #include<cstdio> #include<cstr ...

  3. 队爷的讲学计划 CH Round &num;59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  4. 队爷的Au Plan CH Round &num;59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  5. 队爷的新书 CH Round &num;59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  6. CH Round &num;48 - Streaming &num;3 &lpar;NOIP模拟赛Day1&rpar;

    A.数三角形 题目:http://www.contesthunter.org/contest/CH%20Round%20%2348%20-%20Streaming%20%233%20(NOIP模拟赛D ...

  7. CH Round &num;54 - Streaming &num;5 &lpar;NOIP模拟赛Day1&rpar;

    A.珠 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2354%20-%20Streaming%20%235%20(NOIP模拟赛Day1)/珠 题解:sb题, ...

  8. 10&period;17&lpar;山东多校联合模拟赛 day1&rpar;

    山东多校联合模拟赛 day1 题不难 rect [问题描述] 给出圆周上的 N 个点, 请你计算出以这些点中的任意四个为四个角,能构成多少个矩形. 点的坐标是这样描述的, 给定一个数组 v[1..N] ...

  9. NOI模拟赛 Day1

    [考完试不想说话系列] 他们都会做呢QAQ 我毛线也不会呢QAQ 悲伤ING 考试问题: 1.感觉不是很清醒,有点困╯﹏╰ 2.为啥总不按照计划来!!! 3.脑洞在哪里 4.把模拟赛当作真正的比赛,紧 ...

随机推荐

  1. 伪类before和after

     以你添加的元素为基础!在他的里面!也就是他的内容的前面或者后面添加东西!  如果原来的元素没有内容会出现什么情况?(伪类的宽和高和元素的相等)

  2. console 输出信息

    console.info 用于输出提示性信息 console.error用于输出错误信息 console.warn用于输出警示信息 console.debug用于输出调试信息 console.info ...

  3. Zookeeper-Zookeeper的配置

    前面两篇文章介绍了Zookeeper是什么和可以干什么,那么接下来我们就实际的接触一下Zookeeper这个东西,看看具体如何使用,有个大体的感受,后面再描述某些地方的时候也能在大脑中有具体的印象.本 ...

  4. 高性能的JavaScript库---Lodash

    上周在仿做Nodejs社区的时候,遇到了lodash这个javascript库,很惭愧,那也是我第一次听说lodash.人嘛,对于新鲜的事物总是会或多或少感到些好奇的,于是就毫不犹豫地去lodash官 ...

  5. EF Codefirst 初步学习(二)—— 程序管理命令 更新数据库

    前提:搭建成功codefirst相关代码,参见EF Codefirst  初步学习(一)--设置codefirst开发模式 具体需要注意点如下: 1.确保实体类库程序生成成功 2.确保实体表类库不缺少 ...

  6. git 免密码提交代码

    Linux或者Mac下方法: 创建文件,进入文件,输入内容: cd ~ touch .git-credentials vim .git-credentials https://{username}:{ ...

  7. css3常用样式集锦

    控制线显示0.5px .line:after{ content:""; display:block; position:absolute; width:200%; left:0; ...

  8. Python 基础API

    针对python的os库一些API记录,觉得python的命名并不好,很多API看名字,并不知道具体功能是什么 1. os.path.basename() 得到文件名称,不包括路径,例子:/var/t ...

  9. &lbrack;Nginx&rsqb; Nginx 配置location总结

    cp from : https://www.cnblogs.com/coder-yoyo/p/6346595.html location匹配顺序 "="前缀指令匹配,如果匹配成功, ...

  10. 安装VS提示系统找不到指定路径

    解决办法:删除C:\ProgramData\Package Cache快捷方式