您的位置:首页 > 其它

6.1 考试修改+总结

2016-06-02 10:17 309 查看
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 顺便做做贪心题?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: