XJOI NOI2015训练题7 题解

T1、

原本以为是水题的,但是题目里有这么一句话”模1e9+7“。。。。

可以注意到上下左右都要求单调增,那么状态就很好确定了

f[i][j]表示第一行放了前i个格子,第二行放了前j个格子,并且这些数都是小于等于i+j的

转义很好写:f[i][j]可以推给f[i+1][j]和f[i][j+1]。需要时时保证i>j

另外注意此处格子是否可放。

由于不取模,需要用高精。但是实现只有0.2s

——卡常!

最后还是被卡了20分——本机测试不超时的委屈

订正的时候发现用long long压18位居然就能过了,而9位int死活不过。。。。

还有有些人用这个不算开挂吗? __attribute__((optimize("O2")))

#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
const long long Mod = (1e18);
int a[2][1005];
int n,i,j;
struct BITINT{
  int h;
  long long a[40];
  BITINT operator +(const BITINT &x) const
  {
    if (h==0) return x;
    BITINT ret;
    memset(ret.a,0,sizeof(ret.a));
    ret.h = max(h, x.h);
    for (int i=0;i<ret.h||ret.a[i+1]>0;i++)
    {
      ret.a[i] += a[i]+x.a[i];
      while (ret.a[i]>=Mod)
        ret.a[i+1]++, ret.a[i]-=Mod;
    }
    while (ret.a[ret.h]>0) ret.h++;
    //for (int i=ret.h;i<70;i++) ret.a[i]=0;
    return ret;
  }
  void print(){
    if (h==0) {printf("0\n");return;}
    printf("%lld",a[h-1]);
    for (int i=h-2;i>=0;i--){
      long long x = Mod/10;
      if (a[i]==0) {printf("000000000000000000");continue;}
      while (a[i]<x) {printf("0");x/=10;}
      printf("%lld",a[i]);
    }
    printf("\n");
  }
} f[1005][1005];
 
int main(){
  scanf("%d",&n);
  for (i=1;i<=n;i++)
    scanf("%d",&a[0][i]);
  for (i=1;i<=n;i++)
    scanf("%d",&a[1][i]);
  f[0][0].h = f[0][0].a[0] = 1;
 
  for (i=0;i<=n;i++)
    for (j=0;j<=i;j++)
    if (f[i][j].h>0){
      if (i<n && (a[0][i+1]==0 || a[0][i+1]==i+j+1))
        f[i+1][j] = f[i+1][j] + f[i][j];
      if (j<i && (a[1][j+1]==0 || a[1][j+1]==i+j+1))
        f[i][j+1] = f[i][j+1] + f[i][j];
    }
 
  f[n][n].print();
  return 0;
}

T2、

shtsc2011的原题。

凸包+旋转卡壳,脑补脑补就知道了。。。。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
typedef long long LL;
const int Maxn = 200005;
int n,m,i,j,upcnt,dwcnt;
int opp[Maxn];
double ans, dis1[Maxn], dis2[Maxn];
struct Point
{
  int x, y;
  void read()
  {
    scanf("%d%d",&x,&y);
  }
  bool operator <(const Point &a)const
  {
    return x<a.x || (x==a.x && y<a.y);
  }
  Point operator *(const int &a)const
  {
    return (Point){x*a, y*a};
  }
  Point operator +(const Point &a)const
  {
    return (Point){x+a.x, y+a.y};
  }
  Point operator -(const Point &a)const
  {
    return (Point){x-a.x, y-a.y};
  }
  double len()
  {
    return sqrt(1.*x*x+1.*y*y);
  }
} P, dot[Maxn], up[Maxn], dw[Maxn];
 
int mult(Point P1,Point P2)
{
  if ((LL)P1.x*P2.y>(LL)P1.y*P2.x) return 1;
  if ((LL)P1.x*P2.y<(LL)P1.y*P2.x) return -1;
  return 0;
}
int mult(Point P0,Point P1,Point P2)
{
  return mult(P1-P0,P2-P0);
}
 
void convex_hull(){
  sort(dot+1,dot+n+1);
  up[1] = dot[1]; up[2] = dot[2]; upcnt = 2;
  for (i=3;i<=n;i++){
    while (upcnt>1 && mult(up[upcnt-1],up[upcnt],dot[i])>=0 ) upcnt--;
    up[++upcnt] = dot[i];
  }
  dw[1] = dot[1]; dw[2] = dot[2]; dwcnt = 2;
  for (i=3;i<=n;i++){
    while (dwcnt>1 && mult(dw[dwcnt-1],dw[dwcnt],dot[i])<=0 ) dwcnt--;
    dw[++dwcnt] = dot[i];
  }
 
  for (i=1;i<upcnt;i++) dot[++m] = up[i];
  for (i=dwcnt;i>1;i--) dot[++m] = dw[i];
}
 
void find_opp(int i,int &j){
  for (;true;j=j%m+1){
    int t1 = mult(dot[i%m+1]-dot[i], dot[j]-dot[j-1]);
    int t2 = mult(dot[i%m+1]-dot[i] ,dot[j%m+1]-dot[j]);
    if (t1*t2<=0) return;
  }
}
 
double MULT(Point P1,Point P2)
{
  return 1.*P1.x*P2.y-1.*P1.y*P2.x;
}
 
double Distance(Point P1,Point P2){
  double ret = MULT(P1,P2);
  if (ret<0) ret = -ret;
  ret /= P1.len();
  return ret;
}
 
void calc(int i,int j1,int j2){
  for (int j=j1;j!=j2%m+1;j=j%m+1){
    Point Q = P*2-(dot[i]+dot[j]);
    int t1 = mult(Q,dot[j]-dot[j-1]) * mult(Q,dot[j%m+1]-dot[j]);
    int t2 = mult(Q,dot[i]-dot[i-1]) * mult(Q,dot[i%m+1]-dot[i]);
    if (t1<=0 && t2<=0){
      double d1 = Distance( Q, dot[i]-P );
      double d2 = Distance( Q, dot[j%m+1]-P );
      double d3 = Distance( Q, dot[(j+1)%m+1]-P );
      ans = fmin( ans, fmax(d1, fmax(d2, d3) ) );
    }
  }
}
 
#define fmin(x,y) ( (x)<(y)?(x):(y) )
#define fmax(x,y) ( (x)>(y)?(x):(y) )
const double Eps = 1e-12;
void work(){
  //for (i=1;i<=m;i++) printf("%d %d\n",dot[i].x,dot[i].y);
  dot[0] = dot[m]; ans = 1e18;
  for (i=1,j=3;i<=m;i++){
    find_opp(i,j); opp[i] = j;
    double t1 = Distance( (dot[i%m+1]-dot[i]), (dot[i]-P) );
    double t2 = Distance( (dot[i%m+1]-dot[i]), (dot[i%m+1]-P) );
    double t3 = Distance( (dot[i%m+1]-dot[i]), (dot[j]-P) );
    double t4 = Distance( (dot[i%m+1]-dot[i]), (dot[j%m+1]-P) );
    if (t2>t1) t1 = t2; if (t4>t3) t3 = t4;
    dis1[i] = t1; dis2[i] = t3;
    ans = fmin(ans, fmax(t1, t3) );
  }
  for (i=1;i<=m;i++){
    if (dis2[i]-dis1[i]<=Eps && dis1[i%m+1]-dis2[i%m+1]<=Eps ) calc(i%m+1,opp[i],opp[i%m+1]);
    if (dis1[i]-dis2[i]<=Eps && dis2[i%m+1]-dis1[i%m+1]<=Eps ) calc(i%m+1,opp[i],opp[i%m+1]);
  }
  ans = (double)floor(ans*1000) / 1000.;
  printf("%.3lf\n",ans);
}
 
int main(){
  //freopen("t2.in","r",stdin);
  //freopen("t2.out","w",stdout);
  scanf("%d",&n);
  P.read();
  for (i=1;i<=n;i++)
    dot[i].read();
  convex_hull();
  work();
  return 0;
}

T3、

压轴神题

思路很好

只要我们知道长方形内最高点,最低点,最左点和最右点,预处理这些点之间的上下凸壳就可以合并求答案了。

找最点可以用二分查找矩形内是否有点在logn的时间内搞定。(我会说我之前求矩形内是否有点写的是二维树状数组,平白无故多了两个log然后T得飞起吗?)

用f1[i][j]表示在点i和点j围成的矩形内的上凸壳的面积,f2[i][j]表示在点i和点j围成的矩形内的下凸壳的面积,预处理可以做到O(n^2)

代码很呵呵

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
const int Maxn = 3005;
typedef long long LL;
int n,m,Q,k,i,j,tx,ty;
int a,b,c,d,A,B,C,D;
int nx,ny,upcnt,dwcnt;
int dw[Maxn], up[Maxn];
int ax[Maxn], ay[Maxn];
int sum[Maxn][Maxn];
LL ans, f1[Maxn][Maxn], f2[Maxn][Maxn];
vector <int> ex[Maxn], ey[Maxn];
struct Point
{
  int x, y;
  void read()
  {
    scanf("%d%d",&x,&y);
  }
  bool operator <(const Point &a)const
  {
    return x<a.x || (x==a.x && y<a.y);
  }
  Point operator -(const Point &a)const
  {
    return (Point){x-a.x, y-a.y};
  }
} dot[Maxn], Dot[Maxn];
 
LL mult(Point P0,Point P1)
{
  return (LL)P0.x*P1.y - (LL)P1.x*P0.y;
}
LL mult(Point P0,Point P1,Point P2)
{
  return mult(P1-P0,P2-P0);
}
 
int query(int x1,int x2,int y1,int y2)
{
  return sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];
}
 
void init(){
  for (i=1;i<=n;i++){
    up[1] = i; upcnt = 1;
    for (j=i-1;j>0;j--)
    if (dot[i].y>=dot[j].y)
      {up[++upcnt] = j; break;}
    for (j--;j>0;j--)
    if (dot[i].y>=dot[j].y){
      while (upcnt>1 && mult(dot[up[upcnt-1]], dot[up[upcnt]], dot[j])<=0 ) upcnt--;
      f1[j][i] = f1[up[upcnt]][i] + mult(dot[i], dot[up[upcnt]], dot[j]);
      up[++upcnt] = j;
    }
 
    up[1] = i; upcnt = 1;
    for (j=i+1;j<=n;j++)
    if (dot[i].y>=dot[j].y)
      {up[++upcnt] = j; break;}
    for (j++;j<=n;j++)
    if (dot[i].y>=dot[j].y){
      while (upcnt>1 && mult(dot[up[upcnt-1]], dot[up[upcnt]], dot[j])>=0 ) upcnt--;
      f1[i][j] = f1[i][up[upcnt]] - mult(dot[i], dot[up[upcnt]], dot[j]);
      up[++upcnt] = j;
    }
 
    dw[1] = i; dwcnt = 1;
    for (j=i-1;j>0;j--)
    if (dot[i].y<=dot[j].y)
      {dw[++dwcnt] = j; break;}
    for (j--;j>0;j--)
    if (dot[i].y<=dot[j].y){
      while (dwcnt>1 && mult(dot[dw[dwcnt-1]], dot[dw[dwcnt]], dot[j])>=0 ) dwcnt--;
      f2[j][i] = f2[dw[dwcnt]][i] - mult(dot[i], dot[dw[dwcnt]], dot[j]);
      dw[++dwcnt] = j;
    }
 
    dw[1] = i; dwcnt = 1;
    for (j=i+1;j<=n;j++)
    if (dot[i].y<=dot[j].y)
      {dw[++dwcnt] = j; break;}
    for (j++;j<=n;j++)
    if (dot[i].y<=dot[j].y){
      while (dwcnt>1 && mult(dot[dw[dwcnt-1]], dot[dw[dwcnt]], dot[j])<=0 ) dwcnt--;
      f2[i][j] = f2[i][dw[dwcnt]] + mult(dot[i], dot[dw[dwcnt]], dot[j]);
      dw[++dwcnt] = j;
    }
 
  }
}
 
int find_left(int a,int b,int c,int d){
  int L = a, R = b, t=0;
  while (L<=R){
    int mid = (L+R)>>1;
    if (query(a,mid,c,d)==0) L=mid+1;
      else R=mid-1, t=mid;
  }
  L = 0; R = ex[t].size()-1;
  int ret = 0;
  while (L<=R){
    int mid = (L+R)>>1;
    if (dot[ex[t][mid]].y<ay[c]) L=mid+1;
      else ret=ex[t][mid], R=mid-1;
  }
  return ret;
}
 
int find_right(int a,int b,int c,int d){
  int L = a, R = b, t=0;
  while (L<=R){
    int mid = (L+R)>>1;
    if (query(mid,b,c,d)==0) R=mid-1;
      else L=mid+1, t=mid;
  }
  L = 0; R = ex[t].size()-1;
  int ret = 0;
  while (L<=R){
    int mid = (L+R)>>1;
    if (dot[ex[t][mid]].y>ay[d]) R=mid-1;
      else ret=ex[t][mid], L=mid+1;
  }
  return ret;
}
 
int find_down(int a,int b,int c,int d){
  int L = c, R = d, t=0;
  while (L<=R){
    int mid = (L+R)>>1;
    if (query(a,b,c,mid)==0) L=mid+1;
      else R=mid-1, t=mid;
  }
  L = 0; R = ey[t].size()-1;
  int ret=0;
  while (L<=R){
    int mid = (L+R)>>1;
    if (dot[ey[t][mid]].x<ax[a]) L=mid+1;
      else ret=ey[t][mid], R=mid-1;
  }
  return ret;
}
 
int find_up(int a,int b,int c,int d){
  int L = c, R = d, t=0;
  while (L<=R){
    int mid = (L+R)>>1;
    if (query(a,b,mid,d)==0) R=mid-1;
      else L=mid+1, t=mid;
  }
  L = 0; R = ey[t].size()-1;
  int ret=0;
  while (L<=R){
    int mid = (L+R)>>1;
    if (dot[ey[t][mid]].x>ax[b]) R=mid-1;
      else ret=ey[t][mid], L=mid+1;
  }
  return ret;
}
 
int main(){
  scanf("%d%d",&k,&n);
  for (i=1;i<=n;i++){
    dot[i].read();
    ax[i] = dot[i].x;
    ay[i] = dot[i].y;
  }
  sort(dot+1,dot+n+1);
  sort(ax+1,ax+n+1);
  nx = unique(ax+1,ax+n+1)-ax-1;
  sort(ay+1,ay+n+1);
  ny = unique(ay+1,ay+n+1)-ay-1;
 
  for (i=1;i<=n;i++){
    tx = lower_bound(ax+1,ax+nx+1,dot[i].x)-ax;
    ty = lower_bound(ay+1,ay+ny+1,dot[i].y)-ay;
    ex[tx].push_back(i); ey[ty].push_back(i);
    sum[tx][ty]++;
  }
  for (i=1;i<=nx;i++)
    for (j=1;j<=ny;j++)
      sum[i][j] += sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1];
  init();
 
  scanf("%d",&Q);
  while (Q--){
    scanf("%d%d%d%d",&a,&b,&c,&d);
    a = lower_bound(ax+1,ax+nx+1,a)-ax;
    b = upper_bound(ax+1,ax+nx+1,b)-ax-1;
    c = lower_bound(ay+1,ay+ny+1,c)-ay;
    d = upper_bound(ay+1,ay+ny+1,d)-ay-1;
    //printf("%d %d %d %d\n",a,b,c,d);
    if (query(a,b,c,d)<3) {printf("0\n");continue;}
     
    if (a>=b || c>=d) {printf("0\n");continue;}
    A = find_left(a,b,c,d);
    B = find_right(a,b,c,d);
    C = find_down(a,b,c,d);
    D = find_up(a,b,c,d);
    //printf("%d %d %d %d\n",A,B,C,D);
    if (A==B || C==D) {printf("0\n");continue;}
 
    ans = f1[A][D] + f1[D][B] + f2[A][C] +f2[C][B];
    ans += mult(dot[A], dot[C], dot[D]) + mult(dot[D], dot[C], dot[B]);
    printf("%.1lf\n",(double)ans/2.);
  }
  return 0;
}


你可能感兴趣的:(计算几何,递推)