1. 程式人生 > >[清橙A1210]光稜坦克

[清橙A1210]光稜坦克

[清橙A1210]光稜坦克

題目大意:

平面上放置了\(n(n\le7000)\)個反射裝置,光纖將從某個裝置出發,在經過一處裝置時發生反射,若經過的裝置座標依次為\((x_1,y_1),(x_2,y_2),\ldots,(x_k,t_k)\),則必須滿足:

  • \(\forall j \in (1,k],y_j< y_{j-1}\)
  • \(\forall j\in (2,k],x_{j-2}< x_j < x_{j-1} \vee x_{j-1}< x_j < x_{j-2}\)
    兩種光線不同當且僅當經過的折射裝置的集合不同,求總共有多少種合法的光線。

思路:

一個很顯然的\(\mathcal O(n^3)\)的動態規劃是,首先將所有點按照\(y\)排序,\(f_{i,j}\)表示考慮前\(i\)個裝置,最後一個點是\(i\),上一個點的\(x\)\(j\)的方案數。字首和優化到\(\mathcal O(n^2)\),空間\(\mathcal O(n^2)\)

然而這題要求空間複雜度是\(\mathcal O(n)\)

於是就有了下面\(\mathcal O(n)\)空間的新做法

原始碼:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
    register char ch;
    register bool neg=false;
    while(!isdigit(ch=getchar())) neg|=ch=='-';
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return neg?-x:x;
}
const int N=7002;
struct Point {
    int x,y;
    bool operator < (const Point &rhs) const {
        return x>rhs.x;
    }
};
Point p[N];
int f[N][2];
int main() {
    const int n=getint(),mod=getint();
    for(register int i=1;i<=n;i++) {
        p[i].x=getint();
        p[i].y=getint();
    }
    std::sort(&p[1],&p[n]+1);
    for(register int i=1;i<=n;i++) {
        f[i][0]=f[i][1]=1;
        for(register int j=i-1;j;j--) {
            if(p[j].y<p[i].y) (f[i][0]+=f[j][1])%=mod;
            if(p[j].y>p[i].y) (f[j][1]+=f[i][0])%=mod;
        }
    }
    int ans=mod-n;
    for(register int i=1;i<=n;i++) {
        (ans+=f[i][0])%=mod;
        (ans+=f[i][1])%=mod;
    }
    printf("%d\n",ans);
    return 0;
}