5th Southern Subregional Contest. Saratov 2002 Solution


 

5th Southern Subregional Contest.

Saratov 2002

Solution

Problem A: Thesum

Problem B: Brokenline

Problem C: Shtirlits

Problem D: Boxes

Problem E: Telephonedirectory

Problem F: Snake

Problem G: Inheritance

Problem H: Circle

Problem I: Hardwoodfloor

July 16th,2013 by chlxyd,xioumu


Problem A: Thesum(E)

求斐波拉契数列前k(k<=30)项和。

 

Solution

Tag:暴力

水题。

/*
 * Author:  chlxyd
 * Created Time:  2013/7/16 12:41:28
 * File Name: A.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
int sum[100] , f[100] ;
int main(){
    f[1] = 1 ; f[2] = 1 ;
    repf( i , 3 , 50 ) f[i] = f[i-1] + f[i-2] ;
    repf( i , 1 , 50 ) sum[i] = sum[i-1] + f[i] ;
    int n ;
    while ( scanf("%d" , &n ) == 1 ) {
        printf("%d\n" , sum[n] ) ;
    }
}


 

Problem B: Broken line(N)

给一个多边形,所有边都与坐标轴平行,再给一个点,问这个点是否在多边型内或多边形上

 

Solution

Tag:计算几何

模板题。

有判断点是否在多边形内部的模板。

/*
 * Author:  chlxyd
 * Created Time:  2013/7/16 12:57:10
 * File Name: B.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-13);
const double pi = acos(-1.0);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )

const int maxn = 40000 + 10;

double sgn(double x) {
    return (x > eps) - (x < -eps);
}

struct point {
    double x, y;
    point (double _x = 0, double _y = 0) : x(_x), y(_y) {
    }
    void input() {
        scanf("%lf%lf", &x, &y);
    }
    void output() {
        printf("%lf %lf\n", x, y);
    }
    double len() { 
        return sqrt(x * x + y * y);
    }
    bool operator < (const point &b) const {
        if (sgn(x - b.x) != 0) return x < b.x;
        else return y < b.y;
    }
    bool operator == (const point &b) const { 
        return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
    }
    point operator - (const point &b) const { 
        return point(x - b.x, y - b.y);
    }
    double operator ^ (const point &b) const {
        return x * b.x + y * b.y;
    }
    double operator * (const point &b) const { 
        return x * b.y - y * b.x;
    }
};

double to_normal(double c) {
    if (sgn(c - 1) > 0) return 1;
    else if (sgn(c + 1) < 0) return -1;
    else return c;
}

double get_position(const point &p, const vector<point> &pol, int n) {
    double ang = 0;
    for (int i = 0; i < n; i++) {
        point p1 = pol[i] - p, p2 = pol[(i + 1) % n] - p;
        double c = (p1 ^ p2) / (p1.len() * p2.len());
        c = to_normal(c);
        ang += sgn(p1 * p2) * acos(c);
        if (pol[i] == p) return 0;
    }
    ang = abs(ang);
    return ang < 0.5 * pi ? -1 : (ang < 1.5 * pi ? 0 : 1);
}

vector<point> st, en;
vector<point> all;
int v[maxn];
int n;

void get_all() {
    st.clear();
    en.clear();
    rep (i, n) {
        point x, y;
        x.input();
        y.input();
        st.push_back(x);
        en.push_back(y);
    }
    
    memset(v, 0, sizeof(v));
    int now = 0;
    all.clear();
    while(1) {
        //st[now].output();
        all.push_back(st[now]);
        //printf("%lf\n", now);
        v[now] = 1;
        double old = now;
        rep (i, n)
            if (v[i] == 0) { 
               if (en[now] == st[i] || en[now] == en[i]) {
                    if (en[now] == en[i]) {
                        swap(st[i], en[i]);  
                    }
                    now = i;
                    break;
               } 
            }
        if (now == old) break;
    }
    all.push_back(all[0]);
    //printf("%lf\n", sz(all));
}

int main(){
    while (scanf("%d", &n) == 1) {
        get_all();
        point x;
        x.input();
        double ans = get_position(x, all, n); 
        if (ans == -1) printf("OUTSIDE\n");
        else if (ans == 0) printf("BORDER\n");
        else printf("INSIDE\n");
    }
    return 0;
}


 

Problem C: Shtirlits(N)

给一个n*n的棋盘,里面的数字为1-n*n,问是否存在一种方案使每个点周围四个点比他大的数量和给定数量一样。(n<=3)

 

Solution

Tag:枚举

对于n=1和2的,直接暴力。

对于n =3,枚举(1,1),(1,3),(2,2),(3,1),(3,3)的数字,然后(1,2),(2,1),(2,3),(3,2)四个格子的值是可以计算的,具体的这四个格子的值有两种状态,比如周围格子的值是1,4,5,那么当前格子如果有两个比他大的相邻,那么它可以等于1(与最小相等,情况1),2(与最小不等,情况2),3(同情况2)。所以四个格子各有2种状态,枚举这24状态,然后检查一下整个棋盘是否合法就行,复杂度O(9^6*2^4)。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/16 13:53:05
 * File Name: C.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
bool bj[5][5] ;
int a[5][5] , b[5][5] ;
int n ;
int have ;
bool check( int x , int y ) {
        int h = 0 , i = b[x][y] ;
        if ( i == 0 ) return false ;
        if ( b[x+1][y] > i ) h ++ ;
        if ( b[x][y+1] > i ) h ++ ;
        if ( b[x][y-1] > i ) h ++ ;
        if ( b[x-1][y] > i ) h ++ ;
        if ( h == a[x][y] ) 
            return true ;
        //cout<<x<<" "<<y<<endl;
        return false ;
    
}
bool g( int x , int y , int f ) {
    if ( f == 0 ) {
        b[x][y] = b[x-1][y] ;
        if ( check( x , y ) ) return true ;
        b[x][y] = b[x+1][y] ;
        if ( check( x , y ) ) return true ;
        b[x][y] = b[x][y+1] ; 
        if ( check( x , y ) ) return true ;
        b[x][y] = b[x][y-1] ;
        if ( check( x , y ) ) return true ;
        return false ;
    }
    else if ( f == 1 ) {
        repf( i , 1 , 9 ) {
            if ( b[x-1][y] == i || b[x][y-1] == i || b[x+1][y] == i || b[x][y+1] == i ) continue ;
            b[x][y] = i ;
            if ( check(x,y) ) 
                return true ;
        }
        return false ;
    }
}
void did1() {
    if ( a[1][1] == 0 ) {
        have = 1 ;
        b[1][1] = 1 ;
    }
    else have = 0 ;
}
void did2() {
    have = 0 ;
    repf( a1 , 1 , 4 )
        repf( b1 , 1 , 4 ) 
            repf( c1 , 1 , 4 )
                repf( d1 , 1 , 4 ) {
                    b[1][1] = a1 ; b[1][2] = b1 ;
                    b[2][1] = c1 ; b[2][2] = d1 ;
                    if ( check( 1 , 1 ) && check( 1 , 2 ) && check( 2 , 1 ) && check(2,2) ) {
                        have = 4 ;
                        return ;
                    }
                }
}
void did3() {
    have = 0 ;
    repf( a1 , 1 , 9 ) 
        repf( b1 , 1 , 9) 
        repf( c1 , 1 , 9 ) 
        repf( d1 , 1 , 9 ) 
        repf( e1 , 1 , 9 ) {
            b[1][1] = a1 ; b[1][3] = b1 ; b[2][2] = c1 ; b[3][1] = d1 ; b[3][3] = e1 ;
            repf( f1 , 0 , 1 )
                repf( f2 , 0 , 1 )
                repf( f3 , 0 , 1 )
                repf( f4 , 0 , 1 )
                if ( g(1,2,f1) && g(2,1,f2) && g(2,3,f3) && g(3,2,f4) ) {
            //repf( i , 1 , n ) {
                //repf( j , 1 , n ) {
                    //if ( j != 1 ) printf(" ") ;
                    //printf("%d" , b[i][j] ) ;
                //}
                //cout<<endl ;
            //}
            //cout<<"---------"<<endl;
                    have = 0 ;
                    repf( i , 1 , 3 ) 
                        repf( j , 1 , 3 ) 
                        if ( check(i,j) )
                            have ++ ;
                    //cout<<have<<endl;
                    if ( have == 9 ) return ;
                    //cout<<have<<endl;
                }
        }
}
int main(){
    while ( scanf("%d" , &n ) == 1 ) {
        have = 0 ;
        clr(a) ; clr(b) ; clr(bj) ;
        repf( i , 1 , n ) 
            repf( j , 1 , n )
                scanf("%d" , &a[i][j] ) ;
        if ( n == 1 ) 
            did1() ;
        else if ( n == 2 ) 
            did2() ;
        else did3() ;
        //cout<<have<<endl;
        if ( have == n * n ) {
            repf( i , 1 , n ) {
                repf( j , 1 , n ) {
                    if ( j != 1 ) printf(" ") ;
                    printf("%d" , b[i][j] ) ;
                }
                cout<<endl ;
            }
        }
        else puts("NO SOLUTION") ;
    }
}


Problem D: Boxes(E)

给两个盒子,每个盒子里有一定数量的球,每次把球多的那个盒子拿与球少盒子同等数量的球放到少的那个盒子里去,问最终是否能否使所有球都到一个盒子。

 

Solution

Tag:结论

首先算出和,然后把和的2因子除掉,剩下不被2整除的部分,如果a或b能整除这部分,那么就可行,否则-1。

对于可行,直接暴力求步数就可以了。

/*
 * Author:  chlxyd
 * Created Time:  2013/7/16 13:23:33
 * File Name: D.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
int solve( int a , int n ) {
    if ( a == 0 ) return 0 ;
    return 1 + solve( min( a * 2 , n - a * 2 ) , n ) ;
}
int main(){
    int a , b ;
    while ( scanf("%d %d" , &a , &b ) == 2 ) {
        if ( a < b ) swap( a , b ) ;
        int n = a + b ;
        int have = 1 ;
        while ( n % 2 == 0 ) {
            have *= 2 ;
            n /= 2 ;
        }
        if ( a % n != 0 ) puts("-1" ) ;
        else printf("%d\n" , solve( b / n , have ) ) ;
    }
}

 


Problem E: Telephonedirectory(E)

给一个电话号码放的规则,问一个电话本需要多少页放给定的一些电话。

 

Solution

Tag:模拟

水题。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/16 13:31:59
 * File Name: E.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
int cal( int a , int b ) {
    if ( a == 0 ) return 0 ;
    if ( a % b == 0 ) return a / b ;
    return a / b + 1 ;
}
int n , k ;
char s[10] ;
int have[20] ;
int main(){
    while ( scanf("%d" ,  &k ) == 1 ) {
        clr(have) ;
        scanf("%d" , &n ) ;
        repf( i , 1 , n ) {
            scanf("%s" , s ) ;
            have[s[0]-'0'] ++ ;
        }
        int ans = 2 ;
        repf( i , 0 , 9 )
           ans += cal( have[i] , k ) ;
        printf("%d\n" , ans ) ; 
    }
}


Problem F: Snake(H)

已知平面上N个点以及他们的坐标。所有的坐标 (xi,yi) 都是-10000到10000的整数。用这些点建立一个蛇形折线必须满足以下要求:

1. 蛇形折线必须是闭合折线。

2. 折线的折点必须在给定的N个点中,所有给定的N个点也必须是折线的折点。

3. 折线中任意两个相邻的线段都必须互成90°角。

4. 折线的所有线段都与坐标轴平行。

5. 折线不能自交,不能自我重叠。

6. 满足上述要求的前提下,折线长度要尽可能短。

你只需要计算对于给定的点,能够造出的蛇形折线的长度,或者判断无法构造出这样的折线。 

 

Solution

Tag:计算几何,数据结构

 观察发现,因为一个点连的两条线段必须是90度的角,所以对于一条个X坐标相同的点(假如按y坐标排序后为:p1,p2,p3,p4..pn),他们只能是p1p2连线,p3p4连线.

对于每一Y坐标相同的电也一样。所以假如这个图有解的话,解就是唯一的。所以周长最短的问题就解决了。

然后只需要判断安上面的方法把所有的线段连起来后,连起来的图可以保证时一个或着几个封闭的图,所以只用判断图是不是连通的,和存不存在自交就行了。

判断是不是连通的只要拿并查集或DFS跑一遍就行。

判断存不存在自交可以拿线段树或者树状数组来做。

将所有X相同的线段(竖着的线段)两个端点提出来,记录是起点还是终点(Y小的设为起点,大的设为终点)然后加上Y相同的线段(横着的线段)一起排序,然后按Y的大小从小到大扫描,遇到起点给树状数组对应的X位置加1,遇到终点给对应的X位置减1,遇到横线段判断当前树状数组中在这条线段的X的范围内有没有值。有就是遇到自交了,没有就是这条线段没有自交。

因为在拐角处,两条线会相交,所以排序的时候遇到Y相同的点或者线段要先把终点放前面,线段排第二,起点排最后。

/*
 * Author:  xioumu
 * Created Time:  2013/7/18 13:31:39
 * File Name: F.cpp
 * solve: F.cpp
 */
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<iostream>
#include<vector>
#include<queue>

using namespace std;
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clr(x) memset(x,0,sizeof(x))
#define clrs( x , y ) memset(x,y,sizeof(x))
#define out(x) printf(#x" %d\n", x)
#define sqr(x) ((x) * (x))
typedef long long lint;

const int maxint = -1u>>1;
const double eps = 1e-8;
const int mid = 10000;
const int maxn = 30000 + 100;

int sgn(const double &x) {  return (x > eps) - (x < -eps); }

struct point {
    int x, y;
    point (int _x = 0, int _y = 0) : x(_x), y(_y) {
    }
    void input() {
        scanf("%d%d", &x, &y);
    }
};

struct line {
    point be, en;
    line (point _be, point _en) : be(_be), en(_en) {
    }
};

struct node {
    int ty, x, y, z;
    node (int _ty = 0, int _x = 0, int _y = 0, int _z = 0)
        :ty(_ty), x(_x), y(_y), z(_z) {
        }
};

vector<point> p;
vector<line> l;
vector<node> po;
int ans, n;
int fa[maxn], id[maxn];

int find(int w) {
    if (fa[w] == w) return w;
    int k = find(fa[w]);
    fa[w] = k;
    return k;
}

void combine(int x, int y) {
    int r = find(x), w = find(y);
    if (r != w) 
        fa[w] = r;
}

bool cmpx(const int &a, const int &b) {
    if (p[a].x != p[b].x) return p[a].x < p[b].x;
    else return p[a].y < p[b].y;
}

bool cmpy(const int &a, const int &b) {
    if (p[a].y != p[b].y) return p[a].y < p[b].y;
    else return p[a].x < p[b].x;
}

bool cmpPo(const node &a, const node &b) {
    if (a.y != b.y) return a.y < b.y;
    else if (a.ty != b.ty) return a.ty < b.ty;
    else return a.x < b.x;
}

bool check1() {
    rep (i, n) {
        fa[i] = i;
    }
    sort(id, id + n, cmpx);
    rep (i, n) {
        bool flag = true;
        int bx = p[id[i]].x;
        while (i < n && p[id[i]].x == bx) {
            flag ^= 1;
            if (flag == true) {
                l.push_back(line(p[id[i - 1]], p[id[i]]));
                combine(id[i], id[i - 1]);
            }
            i++;
        }
        if (flag == false) {
            return 0;
        }
        if (i >= n) break;
        i--;
    }
    //puts("test2\n"); 
    sort(id, id + n, cmpy);
    rep (i, n) {
        bool flag = true;
        int by = p[id[i]].y;
        while (i < n && p[id[i]].y == by) {
            flag ^= 1;
            if (flag == true) {
                l.push_back(line(p[id[i - 1]], p[id[i]]));
                combine(id[i], id[i - 1]);
            }
            i++;
        }
        if (flag == false) {
            return 0;
        }
        if (i >= n) break;
        i--;
    }
    int only = find(0);
    rep (i, n)
        if (find(i) != only) {
            return 0; 
        } 
    return 1;
}

int f[maxn];
int lowb(int t) { 
    return t & (-t);
}
void add(int *f, int i, int value) {
    for (; i < maxn; f[i] += value, i += lowb(i));
}

int get(int *f, int i) {
    int s = 0;
    for (; i > 0; s += f[i], i -= lowb(i));
    return s;
}

bool check2() {
    po.clear();
    rep (i, sz(l)) {
        if (l[i].be.x == l[i].en.x) {
            po.push_back(node(2, l[i].be.x + mid, l[i].be.y + mid));
            po.push_back(node(0, l[i].en.x + mid, l[i].en.y + mid));
        }
        else {
            po.push_back(node(1, l[i].be.x + mid, l[i].be.y + mid, l[i].en.x + mid));
        }
    }
    sort(po.begin(), po.end(), cmpPo);
    memset(f, 0, sizeof(f));
    rep (i, sz(po)) {
        if (po[i].ty == 2) {
            add(f, po[i].x, 1);
        }
        else if (po[i].ty == 0) { 
            add(f, po[i].x, -1);
        } 
        else {
            int sum = get(f, po[i].z) - get(f, po[i].x - 1);
            if (sum > 0) return false;
        }
    }
    
    ans = 0;
    rep (i, sz(l)) {
        if (l[i].be.x == l[i].en.x)
            ans += abs(l[i].be.y - l[i].en.y);    
        else 
            ans += abs(l[i].be.x - l[i].en.x);
    }
    return true;
}

int main() {
    while (scanf("%d", &n) == 1) {
        p.clear();
        rep (i, n) {
            point x;
            x.input();
            p.push_back(x);
            id[i] = i;
        }
        ans = 0;
        bool ans1 = check1();
        if (ans1) {
            //puts("ok1\n");
            ans1 = check2();
        }
        printf("%d\n", ans);
    }
    return 0;
}


Problem G: Inheritance(N)

给一个凸包,问一条线段在凸包内的长度。

 

Solution

Tag:计算几何

先求出凸多边形,再求出这条线段与凸多边形的交点,然后求两个交点的长度。

注意,线段在多边形上的部分是不算的。

我是先求出点线段与凸多边形非严格相交的点,再求出在多边型上的端点,还有被线段包含的凸多边形的端点。这3部分点去重后,就是线段与凸多边形的交点,显然点数小于等于2,若点数不为2则答案为0。点数为2,特判这两个点是不是在凸多边形上,是的话答案为0,否则答案为这两个点的长度。

#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-13);
const double pi = acos(-1.0);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )

const int maxn = 40000 + 10;

int sgn(double x) {
    return (x > eps) - (x < -eps);
}

struct point {
    double x, y;
    point (double _x = 0, double _y = 0) : x(_x), y(_y) {
    }
    void input() {
        scanf("%lf%lf", &x, &y);
    }
    void output() {
        printf("%lf %lf\n", x, y);
    }
    double len() { 
        return sqrt(x * x + y * y);
    }
    bool operator < (const point &b) const {
        if (sgn(x - b.x) != 0) return x < b.x;
        else return y < b.y;
    }
    bool operator == (const point &b) const { 
        return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
    }
    point operator - (const point &b) const { 
        return point(x - b.x, y - b.y);
    }
    double operator ^ (const point &b) const {
        return x * b.x + y * b.y;
    }
    double operator * (const point &b) const { 
        return x * b.y - y * b.x;
    }
};

double to_normal(double c) {
    if (sgn(c - 1) > 0) return 1;
    else if (sgn(c + 1) < 0) return -1;
    else return c;
}

int get_position(const point &p, const vector<point> &pol, int n) {
    double ang = 0;
    for (int i = 0; i < n; i++) {
        point p1 = pol[i] - p, p2 = pol[(i + 1) % n] - p;
        double c = (p1 ^ p2) / (p1.len() * p2.len());
        c = to_normal(c);
        ang += sgn(p1 * p2) * acos(c);
        if (pol[i] == p) return -1;
    }
    ang = abs(ang);
    //printf("%f\n", ang);
    return ang < 0.5 * pi ? -1 : (ang < 1.5 * pi ? 0 : 1);
}

void convex(vector<point> a, vector<point> &tu) {
    point hu[maxn], hd[maxn];
    int n = a.size(), un, dn;
    sort(a.begin(), a.end());
    hu[0] = hd[0] = a[0];
    hu[1] = hd[1] = a[1];
    un = dn = 1;
    for (int i = 2; i < n; i++) {
        for (; un > 0 && sgn((hu[un] - hu[un - 1]) * (a[i] - hu[un])) >= 0; un--);
        for (; dn > 0 && sgn((hd[dn] - hd[dn - 1]) * (a[i] - hd[dn])) <= 0; dn--);
        hu[++un] = a[i];
        hd[++dn] = a[i];
    }
    tu.clear();
    for (int i = 0; i <= un - 1; i++) tu.push_back(hu[i]);
    for (int i = dn; i >= 1; i--) tu.push_back(hd[i]);
}

bool inter(point a, point b, point c, point d, point &e) {
    double d1 = (b - a) * (c - a), d2 = (b - a) * (d - a),
           d3 = (d - c) * (a - c), d4 = (d - c) * (b - c);
    if (sgn(d1) * sgn(d2) >= 0 || sgn(d3) * sgn(d4) >= 0) {
        return false;
    }
    e = point((c.x * d2 - d.x * d1) / (d2 - d1),
              (c.y * d2 - d.y * d1) / (d2 - d1));
    return true;
}

vector<point> a, tu;
int n, m;

bool gao(point a, point b) {
    rep (i, sz(tu)) {
        point c = tu[i], d = tu[(i + 1) % sz(tu)];
        double d1 = (b - a) * (c - a), d2 = (b - a) * (d - a),
               d3 = (d - c) * (a - c), d4 = (d - c) * (b - c);
        if (sgn(d1) == 0 && sgn(d2) == 0 && sgn(d3) == 0 && sgn(d4) == 0) {
            //printf("=%d\n", i);
            return true;
        }
    }
    return false;
}

bool in(point a, point b, point c) {
    double p1 = ((b - a) ^ (c - a));
    //a.output();
    //b.output();
    //c.output();
        //printf("%f\n", p1);
        //printf("%d %f\n", sgn((b - a) * (c - a)), (b - a) * (c - a));
    //puts("========");
    if (sgn(p1) <= 0 && sgn((b - a) * (c - a)) == 0) return true;
    else return false;
}

int main() {
    while (scanf("%d", &n) == 1) {
        a.clear();
        rep (i, n) {
            point x;
            x.input();
            a.push_back(x);
        } 
        convex(a, tu);
        scanf("%d", &m);
        rep (i, m) {
            point be, en; 
            be.input();
            en.input();
            vector<point> inte;
            rep (j, sz(tu)) {
                point x;
                bool flag = inter(be, en, tu[j], tu[(j + 1) % sz(tu)], x);   
                if (flag) {
                    inte.push_back(x);
                }
                else if (in(tu[j], be, en)) {
                    inte.push_back(tu[j]);
                }
            }
            
            //printf("%d\n", sz(tu));
            //printf("%d: %d\n", i, get_position(be, tu, sz(tu)));
            //be.output();
            //rep (i, sz(tu)) {
                //tu[i].output();
            //}
            if (get_position(be, tu, sz(tu)) != -1) {
                inte.push_back(be);
                //puts("be");
            }
            if (get_position(en, tu, sz(tu)) != -1) {
                inte.push_back(en);
                //printf("%d\n", get_position(en, tu, sz(tu)));
            }
            
            //printf("sz : %d\n", sz(inte));
            if (sz(inte) == 0) printf("0.00\n");
            else if (sz(inte) == 2) {
                double flag;
                flag = gao(inte[0], inte[1]);
                if (!flag) {
                    printf("%.2f\n", (inte[1] - inte[0]).len());
                }
                else printf("0.00\n");
                //inte[1].output();
                //inte[0].output();
            }
            else {
                printf("0.00\n");
                //inte[2].output();
            }
        }
    }
    return 0;
}


 


Problem H: Circle(E)

一个圆上2k个点,可以连k条边,问这k条边把圆分成的最少部分是多少,有多少种方案。

 

Solution

TagDP

要部分最少那么显然边之间是不会相交的。设f[n]为n条边时的方法总数,则f[n]=f[0]*f[n-2]+f[2]*f[n-4]+…+f[n-2]*f[0]。递归记忆化什么的随便写了。

/*
 * Author:  chlxyd
 * Created Time:  2013/7/16 13:43:03
 * File Name: H.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
long long have[100] ;
long long n ;
void dfs( long long i ) {
    if ( i == 0 ) return ;
    if ( have[i] ) return ;
    long long now = 0 ;
    repf( j , 0 , i - 1 ) {
        dfs(j ) ;
        dfs(i - 1 - j ) ;
        now += have[j] * have[i-1-j] ;
    }
    have[i] = now ;
}
int main(){
    have[0] = 1 ;
    dfs(30) ;
    while ( scanf("%I64d" , &n ) == 1 ) {
        printf("%I64d %I64d\n" , have[n] , n + 1 ) ;
    }
}
 


Problem I: Hardwoodfloor(N)

有1*2和2*2缺一个两种积木,问铺满一个n*m的矩形有多少种拼法。

 

Solution

TagDP

状态F[I][J],I表示前I - 1层都放满了,第I层的二进制状态是J。

然后对于I层的J的状态,可以用DFS把所有能把I层从J状态填满后,对应的I + 1层的状态K搜索出来,然后转移给F[I + 1][K]。

 

/*
 * Author:  chlxyd
 * Created Time:  2013/7/16 13:57:10
 * File Name: I.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (long long i = 0; i < (n); ++i)
#define repf(i, a, b) for (long long i = (a); i <= (b); ++i)
#define repd(i, a, b) for (long long i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
const long long maxn = 10 + 10;
const long long maxmark = 1024 + 100;
long long f[maxn][maxmark];
long long n, m;

long long two(long long w) { 
    return 1 << w;
}

long long have(long long mark, long long w) { 
    return (mark & two(w)) != 0; 
}

long long add(long long mark, long long w) {
    return (mark | two(w));
}

void dfs(long long w, long long k, long long now, long long blow, long long v) {
    if (k == m) {
        f[w][blow] += v;
        //if (w == 1) printf("%I64d\n", now);
        return;
    }
    else {
        if (have(now, k) == 1) { 
            dfs(w, k + 1, now, blow, v);
        } 
        else {
            if (k < m - 1) {
                if (have(now, k + 1) == 0) {
                    dfs(w, k + 2, now, blow, v);
                    if (have(blow, k) == 0) 
                        dfs(w, k + 2, now, add(blow, k), v);
                    if (have(blow, k + 1) == 0) 
                        dfs(w, k + 2, now, add(blow, k + 1), v); 
                }
                if (have(blow, k) == 0 && have(blow, k + 1) == 0) 
                    dfs(w, k + 1, now, add(blow, k) | add(blow, k + 1), v); 
            }
            if (have(blow, k) == 0) 
                dfs(w, k + 1, now, add(blow, k), v);
            if (k > 0) {
                if (have(blow, k) == 0 && have(blow, k - 1) == 0) {
                    dfs(w, k + 1, now, add(blow, k - 1) | add(blow, k), v);
                }
            }
        }
    }
}

int main(){
    while (scanf("%I64d%I64d", &n, &m) == 2) {
        memset(f, 0, sizeof(f));
        f[0][0] = 1;
        rep (i, n) {
           rep (j, two(m)) {
               if (f[i][j] != 0) {
                   dfs(i + 1, 0, j, 0, f[i][j]);
               }
           } 
        }
        //repf (i, 0, n)  {
            //rep (j, two(m)) {
                //printf("%I64d ", f[i][j]);
            //}
            //printf("\n");
        //}
        printf("%I64d\n", f[n][0]);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值