今天真是鬼畜的一场考试,考的是XJOI上的题目
第三题看完题解至今仍是一脸懵逼,完全不懂如何实现
(话说出题人是怎么想到把一个二维问题三维化的OwO
算了算了,前两道题都是送分题,怪不得第三题这么难
先说前两题的题解把
首先第一题
我们可以预处理约数个数函数可以O(1)算出某个b对某个f的贡献
然后我们考虑后面的点的添加状态不会影响到前面的点的状态
又发现当我们做到某个点的时候,由于b>0,所以这个点一定存在一种决策使得这个点对答案有贡献
答案显然是所有的v的和,这样我们可以在O(nlogn)的时间内解决这个问题了
不过貌似由于数据太难构造了,所以貌似随手写写随机化也可以过OwO
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; const int maxn=200010; int n; int b[maxn],f[maxn],v[maxn]; bool vis[maxn]; LL r[maxn],g[maxn],ans; int main(){ scanf("%d",&n); for(int i=1;i<=n;++i){ for(int j=i;j<=n;j+=i)f[j]++; } for(int i=1;i<=n;++i)scanf("%d",&b[i]); for(int i=1;i<=n;++i)scanf("%lld",&r[i]); for(int i=1;i<=n;++i)scanf("%d",&v[i]),ans+=v[i]; for(int i=1;i<=n;++i){ if(g[i]==r[i]){ vis[i]=true; for(int j=i;j<=n;j+=i)g[j]=g[j]+1LL*b[i]*f[j/i]; } } printf("%lld ",ans); for(int i=1;i<=n;++i){ if(vis[i])printf("1 "); else printf("0 "); }return 0; }
第二题
OwO 读完题之后发现是数据结构裸题
离线之后按边权sort一遍做树链剖分用线段树维护一个类似连续子段和的东西就可以了
写的时候一气呵成,直接就拍上了(话说这么裸的数据结构题目真的有写的必要么?
实际上如果这道题目强制在线我们可以不用离线sort直接上主席树就可以了
OwO
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> using namespace std; const int maxn=100010; int n,m,u,v,w; int a[maxn]; int dep[maxn],son[maxn],sz[maxn],fa[maxn]; int pos[maxn],fp[maxn],top[maxn],tot=0; int Ans[maxn]; int anc[maxn][20]; int h[maxn],cnt=0; struct edge{ int to,next; }G[maxn<<1]; struct Edge{ int u,v,w; }c[maxn]; struct ASK{ int x,y,lim,id; }Q[maxn]; struct Seg_Tree{ int pre,suf,val,len; }t[maxn<<2],tmp; bool cmpQ(const ASK &A,const ASK &B){return A.lim>B.lim;} bool cmpc(const Edge &A,const Edge &B){return A.w>B.w;} 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;sz[u]=1; for(int i=h[u];i;i=G[i].next){ if(G[i].to==f)continue; dep[G[i].to]=dep[u]+1; DFS(G[i].to,u);sz[u]+=sz[G[i].to]; if(sz[G[i].to]>sz[son[u]])son[u]=G[i].to; }return; } void Get_pos(int u,int f){ ++tot;pos[u]=tot;fp[tot]=u;top[u]=f; if(!son[u])return; Get_pos(son[u],f); for(int i=h[u];i;i=G[i].next){ if(G[i].to==fa[u]||G[i].to==son[u])continue; Get_pos(G[i].to,G[i].to); }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){ 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 fa[p]; } int Get_Point(int u,int d){ int log; for(log=0;(1<<log)<=dep[u];++log);--log; for(int i=log;i>=0;--i){ if(anc[u][i]!=-1&&dep[anc[u][i]]>d)u=anc[u][i]; }return u; } void build(int o,int L,int R){ if(L==R){t[o].len=1;return;} int mid=(L+R)>>1; build(o<<1,L,mid);build(o<<1|1,mid+1,R); t[o].len=t[o<<1].len+t[o<<1|1].len; } Seg_Tree merge(const Seg_Tree &A,const Seg_Tree &B){ tmp.len=A.len+B.len; tmp.pre=(A.pre!=A.len?A.pre:A.pre+B.pre); tmp.suf=(B.suf!=B.len?B.suf:B.suf+A.suf); tmp.val=A.val+B.val; tmp.val=tmp.val-a[A.suf]-a[B.pre]+a[A.suf+B.pre]; return tmp; } void UPD(int o,int L,int R,int p){ if(L==R){t[o].pre=t[o].suf=1;t[o].val=a[1];return;} int mid=(L+R)>>1; if(p<=mid)UPD(o<<1,L,mid,p); else UPD(o<<1|1,mid+1,R,p); t[o]=merge(t[o<<1],t[o<<1|1]); } Seg_Tree ask(int o,int L,int R,int x,int y){ if(L>=x&&R<=y)return t[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{ Seg_Tree A=ask(o<<1,L,mid,x,y); Seg_Tree B=ask(o<<1|1,mid+1,R,x,y); return merge(A,B); } } Seg_Tree Get_ask(int u,int v){ Seg_Tree cur; bool flag=true; while(top[u]!=top[v]){ Seg_Tree now=ask(1,1,n,pos[top[u]],pos[u]); if(flag)cur=now,flag=false; else cur=merge(now,cur); u=fa[top[u]]; }Seg_Tree now=ask(1,1,n,pos[v],pos[u]); if(flag)cur=now; else cur=merge(now,cur); return cur; } int Get_ans(int u,int v){ if(dep[u]<dep[v])swap(u,v); if(u==v)return 0; int lca=LCA(u,v); if(v==lca){ int tu=Get_Point(u,dep[v]); Seg_Tree A=Get_ask(u,tu); return A.val; }else{ int tu=Get_Point(u,dep[lca]); int tv=Get_Point(v,dep[lca]); Seg_Tree A=Get_ask(u,tu); Seg_Tree B=Get_ask(v,tv); int ans=A.val+B.val; ans=ans-a[A.pre]-a[B.pre]+a[A.pre+B.pre]; return ans; } } int main(){ read(n); for(int i=1;i<n;++i)read(a[i]); for(int i=1;i<n;++i){ read(u);read(v);read(w); u++;v++; add(u,v);add(v,u); c[i].u=u;c[i].v=v;c[i].w=w; }DFS(1,-1);Get_pos(1,1);pre_LCA();build(1,1,n); read(m); for(int i=1;i<=m;++i){ read(Q[i].x);read(Q[i].y);read(Q[i].lim);Q[i].id=i; Q[i].x++;Q[i].y++; } for(int i=1;i<n;++i)if(dep[c[i].u]<dep[c[i].v])swap(c[i].u,c[i].v); sort(Q+1,Q+m+1,cmpQ);sort(c+1,c+n,cmpc); int now=1; for(int i=1;i<=m;++i){ while(now<n&&c[now].w>Q[i].lim){ UPD(1,1,n,pos[c[now].u]); now++; } Ans[Q[i].id]=Get_ans(Q[i].x,Q[i].y); } for(int i=1;i<=m;++i)printf("%d ",Ans[i]); return 0; }
第三题上午更正题意没有听懂更正在说些什么OwO
然后用最小圆覆盖乱写搞模拟退火然后爆零了
后来下午弄懂了更正发现改了改原来模拟退火居然有20分
(然而直接输出yes也有20分
以为200分的挺多的,结果下午过来之后发现大家第一题都挂了OwO
没错,是第一题都挂了。。
我国果然是数据结构大国啊QAQ
第二题AC人数远超第一题AC人数
不过貌似这套题差不多跟NOI day1 难度相仿?