题解

4 条题解

  • 0
    @ 2018-08-12 18:28:03

    考虑一种新方法:括号匹配。
    对于每一个圆,记录其左右分别能到达的最远点l , r。
    显然 l = O(圆心) - R(半径); r = O + R。分别为左括弧和右括弧
    然后得到一个2n的数组。
    对于任意一个圆,其贡献仅有可能为两种:1或2,其中1不必解释,当一个圆被其他圆沿半径方向分为两半,其贡献则为2。
    则考虑括弧匹配,对于任意一个左括弧,记录其贡献值add。有以下情况:

    • 对于连续两个'(',他们的坐标相同,则前面一个的贡献暂时为1。
    • 对于')'的出现,在栈中弹出第一个元素并把他的贡献+1记录到答案
    • 对于连续的两个')'的出现,且坐标相同,则栈顶的'('贡献暂时为1。
    • 对于连续的')'和'('出现,若坐标相同,则栈顶的'('贡献暂时为1。

    非以上情况所述,add均为0。
    最后答案+1,表示最外面的区域。复杂度O(2n)

    #include<cstdio>
    #include<algorithm>
    #define inf 0x3f3f3f3f
    using namespace std;
    int n;
    const int MAXN = 300005;
    struct point{
        int l,r,val,add;
    }p[MAXN<<1];point s[MAXN<<1];point p1,p2;
    
    inline bool cmp(const point a,const point b){
        if(a.val == b.val) return a.r > b.r;
        else return a.val < b.val;
    }
    
    inline void read(int&x){
        x = 0;
        bool flag = false;
        char c = getchar();
        while (c<'0'||c>'9'){ 
            if (c == '-')
                flag = true; 
            c = getchar();
        } 
        while (c>='0'&&c<='9'){
            x = x*10+c-'0';
            c = getchar();
        }
        if (flag)
            x = -x;
    }
    
    int main(){
        read(n);int u = 0;
        for(int i=1;i<=n;++i){
            int o,r;read(o);read(r);
            p1.val = o + r;p2.val = o - r;
            p1.r = 1;p1.l = 0;p2.r = 0;p2.l = 1;
            p1.add = p2.add = 0;
            p[++u] = p1;
            p[++u] = p2;
        }
        sort(p+1,p+1+u,cmp);int tot=0;
        s[++tot] = p[1];int ans = 0;
        int last = inf;
        for(int i=2;i<=u;++i){
            if(p[i].l){
                if(p[i].val == s[tot].val) s[tot].add = 1;
                if(last != inf){
                    if(p[i].val != last) s[tot].add = 0;
                }
                last = inf;
                s[++tot] = p[i];
            }
            if(p[i].r){
                if(last == inf) last = p[i].val;
                else{
                    if(p[i].val !=  last) s[tot].add = 0;
                    last = p[i].val;
                }
                ans += (1 + s[tot].add);
                tot--;
            }
        }
        printf("%d",ans+1);
        return 0;
    }
    
  • 0
    @ 2014-10-06 11:36:45

    既然有人把我的程序发了出来那我就说一下我的做法
    先把圆转化为线段
    找出每个圆的第一个祖先
    意思就是 完全包含而又最小的圆
    然后按左端点递增,左端点相同则右端点越远越优先排序
    每个圆本来只能增加1个平面
    会出现更多 是因为一些圆首尾相接把一个大圆割成了两部分
    那我们只要找出每个圆的一级祖先就可以判断了
    然后求每个圆的一级祖先可以用我在程序中的dfs来求出,正确性应该显然。
    神犇们是否还有更好的做法,求指教?

  • 0
    @ 2014-10-06 11:35:24

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<vector>
    #include<set>
    #include<map>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<list>
    #define FOR(i,a,b) for(i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(i=(a);i>=(b);i--)
    #define mmt(a,b) memset(a,b,sizeof(a))
    #define pb push_back
    #define mp make_pair
    #define y1 fuck
    #define N 700010
    using namespace std;
    typedef long long LL;
    typedef long double LD;
    struct node{int X,Y;}a[N];
    int x[N],r[N],n;
    bool cmp(node a,node b)
    {
    return a.X<b.X||(a.X==b.X&&a.Y>b.Y);
    }
    int divide(int x,int y)
    {
    if (x>=y) return 1;
    int i=x+1,j=x+1,res=0,k;
    while (i<=y)
    {
    while (j<y&&a[j+1].Y<=a[i].Y) j++;
    res+=divide(i,j);
    i=j+1;j++;
    }
    int Max=a[x].X;
    FOR(k,x+1,y)
    if (a[k].X<=Max) Max=max(Max,a[k].Y);
    if (Max==a[x].Y) res+=2;else res+=1;
    return res;
    }
    int main()
    {
    scanf("%d",&n);int i;
    FOR(i,1,n)
    {
    scanf("%d%d",&x[i],&r[i]);
    a[i].X=x[i]-r[i];a[i].Y=x[i]+r[i];
    }
    sort(a+1,a+1+n,cmp);
    int j=1,ans=1;i=1;
    while (i<=n)
    {
    while (j<n&&a[j+1].Y<=a[i].Y) j++;
    ans+=divide(i,j);
    i=j+1;j++;
    }
    printf("%d\n",ans);
    return 0;
    }
    直接模拟即可

  • 0
    @ 2014-10-06 11:23:16

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define L 300010
    using namespace std;
    struct circle
    {
    int lp,rp,IO,father;
    }po[L];
    int n,ans,O,R,nows;
    bool cmp(circle a,circle b)
    {
    if(a.lp==b.lp)
    return a.rp>b.rp;
    return a.lp<b.lp;
    }
    void dfs(int looks)
    {
    while(nows<=n&&po[nows].rp<=po[looks].rp)
    {
    po[nows].father=looks;
    nows++;
    dfs(nows-1);
    }
    return;
    }
    int main()
    {
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
    scanf("%d%d",&O,&R);
    po[i].lp=O-R;
    po[i].rp=O+R;
    }
    sort(po+1,po+n+1,cmp);
    nows=1;
    po[0].rp=2147483647;
    dfs(0);
    for(int i=1;i<=n;i++)
    po[po[i].father].IO+=(po[i].rp-po[i].lp);
    ans=n+1;
    for(int i=1;i<=n;i++)
    if(po[i].IO==po[i].rp-po[i].lp)
    ans++;
    printf("%d\n",ans);
    return 0;
    }

    -------------以上dfs算法来自赵鋆峰,orz orz--------------------------------

  • 1

信息

ID
1883
难度
7
分类
(无)
标签
(无)
递交数
840
已通过
133
通过率
16%
被复制
2
上传者