标签:ring div bsp span memset 关于 size code struct
这道题一看有两个出发现点,一枚举点去找边界,想了一会就Pass了...,二是枚举相框,我们最起码枚举两个边界,然后发现平行边界更好处理,然而仍然只有30分,这个时候就来到了链表的神奇应用,我们枚举上界u,下界d在u的基础之上从下往上枚举,我们每次枚举上界的开始就把上界以下的点建成链表(它的形状大概是在从左到右的基础上对于同一列的从上倒下,就是蛇形),然后让下届去逼近并结算答案,十分巧妙。
关于链表:大概有单向链表,双向链表,以及循环链表,他们作为数据结构的应用十分狭窄,只有在特定情境下才有大用处,所以在oi层面只有双向链表有一定用处,他的删除在记录位置的前提下是O(1)的,查询O(n),插入的话主要是找到合适的位置(前驱),剩下的就是O(1)了。
#include <cstdio> #include <cstring> #include <algorithm> typedef long long LL; const int N=3065; int pre[N],next[N],mem[N][N],last[N]; int line,column,n,k; LL ans; bool ex[N]; struct Point{int x,y;}p[N]; inline bool comp(Point a,Point b){return a.y<b.y||(a.y==b.y&&a.x<b.x);} int main(){ scanf("%d%d%d%d",&line,&column,&n,&k); for(int i=1;i<=n;++i) scanf("%d%d",&p[i].x,&p[i].y); std::sort(p+1,p+n+1,comp); for(int i=1;i<=n;++i) mem[p[i].x][++mem[p[i].x][0]]=i; for(int u=1;u<=n;++u){ int pr=0;memset(ex,0,sizeof(ex)); for(int i=u;i<=n;++i) for(int j=1;j<=mem[i][0];++j) ex[mem[i][j]]=true,last[mem[i][j]]=line; for(int i=1;i<=n;++i) if(ex[i])pre[i]=pr,next[pr]=i,pr=i; pre[n+1]=pr,next[pr]=n+1; for(int i=2;i<=k;++i) pre[n+i]=n+i-1,next[n+i-1]=n+i; for(int d=n;d>=u;--d){ for(int i=1;i<=mem[d][0];++i){ int nk=mem[d][i]; for(int j=1;j<=k;++j)nk=next[nk]; if(next[mem[d][i]]<=n&&p[next[mem[d][i]]].x!=d) ans+=(LL)(last[next[mem[d][i]]]-d+1)* (p[next[mem[d][i]]].y-p[pre[next[mem[d][i]]]].y)* (nk>n?0:column-p[nk].y+1), last[next[mem[d][i]]]=d-1; nk=pre[nk], ans+=(LL)(last[mem[d][i]]-d+1)* (p[mem[d][i]].y-p[pre[mem[d][i]]].y)* (nk>n?0:column-p[nk].y+1); for(int j=1,now=mem[d][i];j<k&&now;++j){ now=pre[now],nk=pre[nk]; if(now&&p[now].x!=d&&last[now]>=d) ans+=(LL)(last[now]-d+1)* (p[now].y-p[pre[now]].y)* (nk>n?0:column-p[nk].y+1), last[now]=d-1; } } for(int i=1;i<=mem[d][0];++i) next[pre[mem[d][i]]]=next[mem[d][i]], pre[next[mem[d][i]]]=pre[mem[d][i]]; } } printf("%lld",ans); }
标签:ring div bsp span memset 关于 size code struct
原文地址:http://www.cnblogs.com/TSHugh/p/7617788.html