6.1 考试修改+总结

QAQ 终于回到衡中了,昨天做了一个晚上的火车,所以没来的及补题解

Em 儿童节快乐,撒花~~

第一题

NOIP难度?提到国王游戏都提醒你怎么做了

直接裸上排序不等式化简一下就可以了

具体化简过程就不再赘述了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=100010;
int T,n;
struct OP{
    LL a,b;
}c[maxn];
LL sum,ans,tmp;

bool cmp(const OP &A,const OP &B){
    return A.a+B.b+max(A.b,B.a)<B.a+A.b+max(A.a,B.b);
}
void read(LL &num){
    num=0;char ch=getchar();
    while(ch<‘!‘)ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-‘0‘,ch=getchar();
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)read(c[i].a),read(c[i].b);
        sort(c+1,c+n+1,cmp);
        sum=tmp=ans=0;
        for(int i=1;i<=n;++i){
            sum+=c[i].a;
            tmp=max(tmp,sum)+c[i].b;
        }ans=tmp;
        printf("%lld\n",ans);
    }return 0;
}

第二题

貌似是在湖南雅礼培训的时候考过的原题?

现在看看是二维曼哈顿距离最小生成树的裸题

随便写写之后在树上做一下倍增就可以了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn=100010;
const int oo=0x7fffffff;
int n,m,cnt=0;
int u,v;
struct Edge{
    int u,v,w;
}c[1000010];
int tmp[maxn];
int fa[maxn];
int anc[maxn][20];
int mx[maxn][20];
int dep[maxn];
int h[maxn],tot=0;
struct edge{
    int to,next,w;
}G[maxn<<1];
struct pos{
    int x,y,id;
}p[maxn],P[maxn];
struct BIT{
    int mn,p;
}t[maxn];

int ufs(int x){return fa[x]==x?x:fa[x]=ufs(fa[x]);}
bool cmp(const pos &A,const pos &B){
    if(A.x==B.x)return A.y<B.y;
    return A.x<B.x;
}
bool cmpdis(const Edge &A,const Edge &B){
    return A.w<B.w;
}
void add(int x,int y,int z){
    ++tot;G[tot].to=y;G[tot].next=h[x];G[tot].w=z;h[x]=tot;
}
int sqr(int x){return x*x;}
int dis(int i,int j){
    return abs(P[i].x-P[j].x)+abs(P[i].y-P[j].y);
}
int lowbit(int x){return x&(-x);}
void UPD(int x,int mn,int id){
    for(int i=x;i<=m;i+=lowbit(i)){
        if(t[i].mn>mn){
            t[i].mn=mn;t[i].p=id;
        }
    }return;
}
int ask(int x){
    int mn=oo,p=-1;
    for(int i=x;i>=1;i-=lowbit(i)){
        if(t[i].mn<mn){
            mn=t[i].mn;p=t[i].p;
        }
    }return p;
}
void make_Graph(){
    for(int flag=0;flag<4;++flag){
        if(flag==1||flag==3)for(int i=1;i<=n;++i)swap(p[i].x,p[i].y);
        else if(flag==2)for(int i=1;i<=n;++i)p[i].y=-p[i].y;
        for(int i=1;i<=n;++i)tmp[i]=p[i].x-p[i].y;
        sort(tmp+1,tmp+n+1);
        m=unique(tmp+1,tmp+n+1)-tmp-1;
        sort(p+1,p+n+1,cmp);
        for(int i=1;i<=n;++i)t[i].mn=oo,t[i].p=-1;
        for(int i=n;i>=1;--i){
            int Pos=lower_bound(tmp+1,tmp+m+1,p[i].x-p[i].y)-tmp;
            int cur=ask(Pos);
            if(cur!=-1){
                ++cnt;
                c[cnt].u=p[i].id;c[cnt].v=cur;
                c[cnt].w=dis(c[cnt].u,c[cnt].v);
            }UPD(Pos,p[i].x+p[i].y,p[i].id);
        }
    }return;
}
void Kruscal(){
    sort(c+1,c+cnt+1,cmpdis);
    for(int i=1;i<=n;++i)fa[i]=i;
    for(int i=1;i<=cnt;++i){
        int d1=ufs(c[i].u),d2=ufs(c[i].v);
        if(d1!=d2){
            fa[d1]=d2;
            add(c[i].u,c[i].v,c[i].w);
            add(c[i].v,c[i].u,c[i].w);
        }
    }return;
}
void DFS(int u,int f){
    anc[u][0]=f;
    for(int i=h[u];i;i=G[i].next){
        int v=G[i].to;
        if(v==f)continue;
        mx[v][0]=G[i].w;
        dep[v]=dep[u]+1;
        DFS(v,u);
    }return;
}
void pre_LCA(){
    for(int i=1;i<=n;++i){
        for(int j=1;(1<<j)<=n;++j)anc[i][j]=-1,mx[i][j]=-oo;
    }
    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];
                mx[i][j]=max(mx[i][j-1],mx[a][j-1]);
            }
        }
    }return;
}
int LCA(int p,int q){
    if(dep[p]<dep[q])swap(p,q);
    int log,ans=0;
    for(log=0;(1<<log)<=dep[p];++log);--log;
    for(int i=log;i>=0;--i){
        if(dep[p]-(1<<i)>=dep[q]){
            ans=max(ans,mx[p][i]);
            p=anc[p][i];
        }
    }
    if(p==q)return ans;
    for(int i=log;i>=0;--i){
        if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){
            ans=max(ans,mx[p][i]);p=anc[p][i];
            ans=max(ans,mx[q][i]);q=anc[q][i];
        }
    }ans=max(ans,mx[p][0]);ans=max(ans,mx[q][0]);
    return ans;
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y),p[i].id=i,P[i]=p[i];
    make_Graph();Kruscal();
    DFS(1,-1);pre_LCA();
    scanf("%d",&m);
    while(m--){
        scanf("%d%d",&u,&v);
        if(u==v){printf("0\n");continue;}
        printf("%d\n",LCA(u,v));
    }return 0;
}

第三题

第三题失误好大。。一开始看题第一感dp,然后就陷在dp中拔不出来了

这道题目最大的性质就是一个点只能增加不能减少

如果可以减少的话就是只能写架设电话线那种O(n*a)的dp了

我们考虑每个点只能增加,那么一个点当且仅当左右都比他高的时候增加才是有意义的

但是一个点的高度增加之后可能会对其他点是否增加产生影响

不难发现只有高度比这个点小的点增加才会对这个点产生影响

那么我们把点从小到大排序依次增加就可以了

问题就转化成了如何O(1)的计算要增加多少以及代价

然后考虑每一步的收益,拆掉x^2变成每一步是2*base+1(base是之前增高的次数)

用并查集维护联通块内的sigma(base)就可以了,化简一下式子就可以O(1)判断了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std;

const int maxn=100010;
const int oo=0x7fffffff/3;
typedef long long LL;
int cnt;
LL n,c,ans;
LL Num,mx,sz;
LL a[maxn];
LL sum[maxn];
int pre[maxn],nxt[maxn];
int L[maxn],R[maxn];
int val[maxn];
int fa[maxn];
struct OP{
    int v,id;
}t[maxn];
bool cmp(const OP &A,const OP &B){return A.v<B.v;}
int ufs(int x){return fa[x]==x?x:fa[x]=ufs(fa[x]);}
void del(int x){pre[nxt[x]]=pre[x];nxt[pre[x]]=nxt[x];}

int main(){
    scanf("%lld%lld",&n,&c);
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    a[0]=oo;cnt=0;
    for(int i=1;i<=n;++i){
        if(a[i]!=a[i-1]){
            ++cnt;
            pre[cnt]=cnt-1;
            nxt[cnt]=cnt+1;
            L[cnt]=i;R[cnt]=i;
            val[cnt]=a[i];
        }else R[cnt]++;
    }nxt[0]=1;pre[cnt+1]=cnt;
    for(int i=1;i<=cnt;++i)fa[i]=i,t[i].v=val[i],t[i].id=i;
    fa[0]=0;fa[cnt+1]=cnt+1;
    sort(t+1,t+cnt+1,cmp);
    for(int i=1;i<cnt;++i){
        int now=ufs(t[i].id);
        Num=2;sz=R[now]-L[now]+1;mx=0;
        int l=ufs(pre[now]),r=ufs(nxt[now]);
        if(l==0||r==cnt+1){
            Num=1;
            if(l==0)mx=val[r]-val[now];
            else mx=val[l]-val[now];
        }else mx=min(val[l],val[r])-val[now];
        if(mx<=0){continue;}
        LL tmp=(Num*c-2*sum[now]-sz)/(2*sz);
        if(2*sum[now]+sz>Num*c)tmp=-1;
        if(tmp>=mx-1){
            ans=ans+mx*mx*sz+2*mx*sum[now];
            sum[now]+=mx*sz;
            val[now]+=mx;
            if(val[now]==val[l]&&val[now]==val[r]){
                sum[now]+=sum[l]+sum[r];
                L[now]=L[l];R[now]=R[r];
                fa[l]=now;fa[r]=now;
                del(l);del(r);
            }else if(val[now]==val[l]){
                sum[now]+=sum[l];
                L[now]=L[l];fa[l]=now;
                del(l);
            }else{
                sum[now]+=sum[r];
                R[now]=R[r];fa[r]=now;
                del(r);
            }
        }else if(tmp>=0){
            ans=ans+(tmp+1)*(tmp+1)*sz+2*(tmp+1)*sum[now];
            sum[now]+=(tmp+1)*sz;
            val[now]+=tmp+1;
        }
    }
    LL la=val[ufs(nxt[0])];
    for(int k=ufs(nxt[ufs(nxt[0])]);k&&k!=cnt+1;k=ufs(nxt[k])){
        ans=ans+abs(val[k]-la)*c;
        la=val[k];
    }
    printf("%lld\n",ans);
    return 0;
}

第三题的失误好大的QAQ

主要是没有发现只能增加的性质,也就是这个性质决定了贪心的正确性

但是现在想想,就是考场上我想出贪心也不敢去写

贪心功力太差,正确性的证明能力决定了自己的信心

看来以后要学一学数学了 QAQ 顺便做做贪心题?

时间: 2024-10-25 21:59:24

6.1 考试修改+总结的相关文章

5.28 考试修改+总结

今天又是一个悲伤的故事,所有排名比我高的人第一题都A了 而我第一题爆零了 但是开心的事情是:第一题没有说是简单图,所以题解是错的 不管怎么样,将错就错吧 今天下午断网了,所以这时候才写blog 第一题 由于题目中没有给出欧拉图的概念,所以我完全不知道它在说啥,于是就爆零了 然后欧拉图就是存在欧拉回路的简单图,具有以下特点: 1.联通 2.度数都是偶数 显然我们将错就错看题目的话,把欧拉图数目*(n*(n-1)/2+1)就可以得到答案了 然后我们很容易知道度数均为偶数的图的数目是2^((n-1)*

6.15 考试修改+总结

昨天考崩了QAQ 几乎写全了暴力分,然而并没有什么卵用 因为只要A掉一道题就比我分高了,比我分高的也至少A掉了一道题QAQ 感觉到一丝淡淡的忧桑 貌似THUSC最后听讲课的那些人几乎都A了两题 看来我的THUSC果然只是RP好啊 第一题 显然选色数最少的颜色,设颜色数为m 考虑存在某个点的方案数,设这个点到k距离i个点 则方案数为(n-1-i)!/ ((m-i)!*j!*k!……) j,k等是其他颜色的色数 总方案也是非常好算的,这样我们就可以计算每个点对于期望的贡献了 这样做是O(n^2)的

5.26 考试修改+总结

论写5K+的代码在只有样例的条件下都可以调对 由此可见,勇气才是成功的关键 先放题解吧 第一题上午写的暴力不小心忘记题目换根之后还会染色了 然后就挂成了5分QAQ 有很大的部分分是SDOI染色,还有一部分是旅行 但是考试犯懒没有写 很容易发现任何一种颜色在树上都是连续的一段 那么我们不妨这么定义,如果一条边两端颜色不相同,我们定义为虚边,会对子树每个答案产生+1的贡献 如果两端颜色相同,我们定义为实边,不会产生贡献 不难发现,这样定义后的实边和虚边的性质和LCT的定义是一样的 我们考虑使用LCT

6.3 考试修改+总结

今天下午考试被FFT和数论题目翔了一脸QAQ 做的是Newscafe杯的题目 第一题 异化多肽 显然构造多项式f 答案是f+f^2+f^3…… 化简一下得1/(1-f) 之后多项式求逆即可 考试的时候推了好久的多项式求逆的式子(感觉自己什么都忘光了 #include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #include<algorithm> #define

6.11 考试修改+总结

第三题至今没敢写,感觉好恐怖QAQ 今天考得好糟糕 第一题只写了10分的暴力+(k=1)20分的网络流 后来题解告诉我k>1的时候可以分治到k=1,每层分治解决方法是同k=1的 考试的时候没有注意到2^k这个比较神奇的可以分治的性质 而且自己考场上丝薄了,没有发现因为是二分图可以直接跑欧拉回路的性质,而是裸套网络流模型 第二题其实已经接近想出了题解 自己考试的时候成功证明了暴力的复杂度是线性的 但是没有想到如何寻找0-1对,然后就只能暴力用Splay维护1所在的位置了 默默祈祷数据不要太卡我的做

6.10 考试修改+总结+颓废记

昨天晚上得到了非常不爽的消息,zcg要去给高一讲课,而我并不能去 虽然什么事情并不能都顺着我的心意来吧,但是这件事情真是让人越想越不痛快 要知道,我从去年就一直期待着给高一讲课呢 所以今天考试非常不开心,一般这个时候我会选择爆零的 但是想了想觉得爆零太难看,就看了看好像第一题可做 在教学楼里颓废了好久然后吃了点东西,用最后的时间码完了第一题 (反正二.三题我没看出来怎么做,所以暴力也不想写了 然后惊讶的是,只有第一题程序的窝rank1了QAQ 先放题解吧 第一题: 首先我们注意到转置的实质是某个

5.27 考试修改+总结

这是一个悲伤的故事 上午写manacher的时候往里面加#号,然后统计有效字符的个数 然后我就开始模拟,一个长度为6的串我都能数错有多少个有效字符 我把2个字符数成了3个!然后暴力就挂掉了5分.. 为什么这几天的暴力总是会挂掉,真是奇怪(看来是最近自己内心不太稳了 (大概是被那个梦吓得吧QAQ) 今天又A了两道题目,感觉天天都是两道正解+挂掉的暴力QAQ 先放题解吧 第一题是之前数位DP坑掉的题目,然后今天尝试着写了写,感觉不是很难 但是并不是用数位DP做的 先考虑加密的情况,我们只需要统计每一

6.19 考试修改+总结

QAQ 又是一套水题集合 然后忧伤的故事是老师把时间调到了四个小时半 我又因为想要出道题花了半个小时写了一些其他的东西 然后最后没有写完题!QAQ 不然第三题可能多拿点分 上午的时候把所有题目的正解都想了出来 唯一美中不足的是自己想的第三题是O(n^4*300)的是时间复杂度 实际上离散化区间之后只会有n个区间,时间复杂度就是O(n^5)了QAQ 先说题解把 第一题 决战圆锥曲线 显然给定你的那个函数a*x+b*y+c*x*y对于x,y是相对等价的 又因为题目的输入具有随机性,显然可以通过维护线

5.25 考试+修改

论改题只用两分钟的速度QAQ 其实就是换了个数组名字,加上加了一句话 第一题: 首先考虑k=1的情况,考虑构造转移矩阵A ans*(A^0+A^1+……+A^(n-1)) 然后括号里的式子等比数列求和一下 是(A^0-A^n)/(A^0-A^1) 涉及到除法,手动矩阵求逆就可以了 然后这个式子就变成了一个矩阵 我们考虑k>1的情况,发现扩维不过就是又乘了一次这个矩阵 然后把这个矩阵自乘k次即可 (考试的时候犯傻,没有想到k>1的时候直接自乘k次就可以了,下午加了一句话就A了) #include