zoukankan      html  css  js  c++  java
  • BZOJ5324 JXOI2018 守卫

    传送门

    这是我见过的为数不多的良心九怜题之一

    题目大意

    给定一段$n$个点构成的折线,第$i$个折点的坐标是$(i,h_i)$,你可以在$i$点放置一个视野,定义$i$能看到$j$当且仅当$i$处有视野且$jleq i$且$(i,h_i)$到$(j,h_j)$的连线段除了两个端点都严格地在折线上方。一段区间$[L,R]$对答案的贡献是能看到至少整个$[L,R]$的需要的视野最小数量,求所有区间答案的异或和。

    题解

    考虑一段区间$[L,R]$,$R$一定要选,对于每一个$R$端点看不到的点$x$,若$x+1$能被看到,则一定要在$x+1$处或$x$处放置视野才行。

    所以区间$DP$,预处理两点之间可否互相看到,枚举右端点,从右向左扫,对于最左侧连续的一段$r$看不到的点,设$[l,k]$是这段区间,则$F_{l,r}=min{F_{l,k},F_{l,k+1}}+F_{k+1,r}$,否则$F_{l,r}=F_{l+1,r}$。

    #include<bits/stdc++.h>
    #define M 5020
    #define LL long long
    using namespace std;
    int n,m,p[M],F[M][M],ans; bool can[M][M];
    int read(){
        int nm=0,fh=1; char cw=getchar();
        for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
        for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
        return nm*fh;
    }
    int main(){
        n=read(); for(int i=1;i<=n;i++) p[i]=read(),F[i][i]=F[i-1][i]=1;
        for(int i=1;i<=n;i++){
            for(int ht=-1,j=1,pos=1;i+j<=n;j++){
                if((LL)(ht-p[i])*(LL)j>=(LL)(p[i+j]-p[i])*(LL)pos) can[i][i+j]=false;
                else can[i][i+j]=true,pos=j,ht=p[i+j];
            }
        } ans=1;
        for(int r=3;r<=n;++r){
            for(int last=0,l=r-2;l;--l){
                if(can[l][r]) last=0,F[l][r]=F[l+1][r];
                else if(last) F[l][r]=F[last+1][r]+min(F[l][last],F[l][last+1]);
                else F[l][r]=F[l+1][r]+1,last=l; ans^=F[l][r];
            }
        } printf("%d
    ",ans); return 0;
    }
  • 相关阅读:
    java 泛型详解
    Vector源码解析
    栈的应用 函数调用
    java中ArrayList 遍历方式、默认容量、扩容机制
    java代码实现自定义栈 + 时间复杂度分析
    mySql分页Iimit优化
    Mybatis 动态SQL注解 in操作符的用法
    设计模式之 外观模式
    设计模式之 装饰器模式
    设计模式之 组合模式
  • 原文地址:https://www.cnblogs.com/OYJason/p/9821796.html
Copyright © 2011-2022 走看看