2012省赛

来源:互联网 发布:linux新建文档命令 编辑:程序博客网 时间:2024/04/25 03:36

B题, 简单搜索

int dx[] = { -1,1, 2, 2, -1,1 ,-2,-2 };int dy[] = { 2,2 , -1 , 1 ,-2 , -2 , 1 , -1};int bx[] = { 0,1 ,0,-1 };int by[] = { 1,0,-1,0};int ans, n, m, k, ld;int map[10][10];bool can(int x, int y){    return x>=0 && x<n && y>=0 && y<m;}void dfs(int x, int y, int d){    if(!can(x, y))        return ;    if(map[x][y])return;    if(ld==d)    {        ans++;        return;    }    map[x][y]=1;    for (int i=0; i<4; ++i)    {        int bbx=x+bx[i];        int bby=y+by[i];        if(!can(bbx, bby))continue;        if(map[bbx][bby]==2)            continue;        int nx=x+dx[i<<1];        int ny=y+dy[i<<1];        dfs(nx, ny, d+1);        nx=x+dx[i<<1|1];        ny=y+dy[i<<1|1];        dfs(nx, ny, d+1);    }    map[x][y]=0;}int main (){    while (~scanf("%d%d%d", &n, &m, &k))    {        if(k==-1)            break;        memset (map, 0, sizeof(map));        ans=0;        for (int i=0; i<k; ++i)        {            int a, b; scanf("%d%d", &a, &b);            a--, b--;            map[a][b]=2;        }        ld=m*n-k;        dfs(0, 0, 1);        printf("%d\n", ans);    }    return 0;}



C题, 枚举每对在同一直线上的2点, 在找纵坐标在2点间的x的最大值, 用区间最值RMQ, st算法O(1)找出, 区间要先对纵坐标离散化


using namespace std;const int maxn=2000+123;struct Node{    int x, y, id;}node[maxn];bool cmp1(Node a, Node b){    return a.y<b.y;}bool cmp2(Node a, Node b){    if(a.x==b.x)return a.y<b.y;    return a.x<b.x;}///int a[maxn], dp[maxn][50];int bit(int x)// bit-op for getting first non-zero bit{    if(x==0)return 0;    int n=31;    if((x>>16)==0){n-=16; x<<=16;}    if((x>>24)==0){n-=8; x<<=8;}    if((x>>28)==0){n-=4; x<<=4;}    if((x>>30)==0){n-=2; x<<=2;}    return n-(x>>31);}void ST(int x)// for st-table{    for (int i=0; i<x; ++i)        dp[i][0]=a[i];    int lgx=bit(x);    //printf("%d %d %d\n", x, lgx, lgx1);    for (int i=1; i<=lgx; ++i)    {        for(int j=x-1; j>=0; --j)        {            dp[j][i]=dp[j][i-1];            if(j+(1<<(i-1))<=x)dp[j][i]=max(dp[j][i], dp[j+(1<<(i-1))][i-1]);        }    }}int RMQ(int s, int t){    int lgx=bit(t-s+1)-1;    //printf("%d %d %d\n", lgx, lgx1, t-s+1);    return max(dp[s][lgx], dp[t-(1<<lgx)+1][lgx]);}int main (){    int cas; scanf("%d", &cas);    for (int I=1; I<=cas; ++I)    {        int n; scanf("%d", &n);        for (int i=0; i<n; ++i)        {            scanf("%d%d", &node[i].x, &node[i].y);            node[i].id=0;        }        sort(node, node+n, cmp1);        node[0].id=0;        int cnt=0;        memset (a, 0, sizeof(a));        for (int i=1; i<n; ++i)        {            if(node[i].y!=node[i-1].y)                node[i].id=++cnt;            else node[i].id=cnt;        }        for (int i=0; i<n; ++i)        {            a[node[i].id]=max(a[node[i].id], node[i].x);            //printf("a[%d]= %d\n", node[i].id, a[node[i].id]);        }        ST(cnt+1);        sort(node, node+n, cmp2);        int ans=-1, t;        for (int i=0, seg=0; i<n; ++i)        {            for (int j=i+1; j<n; ++j)            {                if(node[i].x!=node[j].x)                    break;                if(node[i].id+1<=node[j].id-1)                {                    t=RMQ(node[i].id+1, node[j].id-1);                    if(t-node[i].x>node[j].y-node[i].y)                        ans=max(ans, node[j].y-node[i].y+t-node[i].x);                    //printf("%d %d %d %d\n", node[i].id+1, node[j].id-1, t, a[node[i].id+1]);                }            }        }        printf("Case %d: %d\n", I, ans);    }    return 0;}





E题, DP 三维状态, 按行分阶段, dp[i][j][k]表示走到第i行2人位置分别为j,k的最小值

const int MAXN = 1001;int dp [MAXN][12][12];const int inf = 0x7fffffff;char lc[MAXN][20];int abs ( int x ){    return x < 0 ? -x : x ;}int main(){    int n , m , mi , ma , x , y;    int Case;    scanf("%d",&Case );    for ( int k = 1 ; k <= Case ;k ++ )    {        scanf("%d%d%d%d%d%d",&n,&m,&mi,&ma,&x,&y);        getchar();        for ( int i =0  ; i < n ; i ++ )            for ( int l = 0 ; l < m ; l ++ )                for ( int c = 0 ; c < m; c ++ )                    dp[i][l][c] = inf;        dp[0][x][y] = 0;        for ( int i = 0 ; i < n ; i ++) scanf("%s",lc[i]);        for ( int i = 1 ; i < n ; i ++ )            for ( int l = 0 ; l < m ; l ++ )                for ( int c = l+mi ; c <= l+ma && c < m ; c ++ )                {                    if ( lc[i][l] == '.' || lc[i][c] == '.' )                        continue;                    for ( int l1 = 0 ; l1 < m; l1 ++ )                        for ( int c1 = l1+mi ; c1 <= l1+ma && c1 < m; c1 ++ )                        {                            if ( dp[i-1][l1][c1] == inf )                                continue;                            if ( dp[i][l][c] > dp[i-1][l1][c1] + abs(l-l1) + abs(c-c1) )                                dp[i][l][c] = dp[i-1][l1][c1] + abs(l-l1) + abs(c-c1);                }        int ans = inf;        for ( int i = 0 ; i < m ;i ++ )            for ( int j = 0 ; j < m; j ++ )                if ( ans > dp[n-1][i][j] )                    ans = dp[n-1][i][j];        if ( ans == inf )            ans = -1;        printf("%d\n" ,ans );    }    return 0;}


F题 , 计算几何, 用到一些简单的数学几何知识和三角函数公式,先求出原点到圆心所在直线的斜率, 然后利用tan公式求出上下切线的斜率, 再求出映射到x=d的区间, 之后扫一遍 求出阴影的长度并。

struct segment{    double y1, y2;}seg[150];double calc_k1( double a, double b, double r ){    double tan1, tan2;    tan1 = r / ( sqrt( a * a + b * b - r * r ) );    tan2 = b / a;    return ( tan1 + tan2 ) / ( 1 - tan1 * tan2 );}double calc_k2( double a, double b, double r ){    double tan1, tan2;    tan1 = r / ( sqrt( a * a + b * b - r * r ) );    tan2 = b / a;    return ( tan2 - tan1 ) / ( 1 + tan1 * tan2 );}double calc_pt1( double k1, double y ){    return k1 * y;}double calc_pt2( double k2, double y ){    return k2 * y;}bool cmp(segment a, segment b){    if(a.y1==b.y1)return a.y2>b.y2;    return a.y1>b.y1;}int main(){    double d;    int n;    double x, y, r;    while( cin >> d >> n, n )    {        for( int i = 0; i < n; i++ )        {            cin >> x >> y >> r;            double k1 = calc_k1( x, y, r );            double pt1 = calc_pt1( k1, d );            double k2 = calc_k2( x, y, r );            double pt2 = calc_pt2( k2, d );            seg[i].y1 = pt1;            seg[i].y2 = pt2;        }        sort( seg, seg + n, cmp );        double ans = 0.0;        ans = seg[0].y1 - seg[0].y2;        double lowest = seg[0].y2;        for (int i=1 ; i<n; ++i)        {            if( seg[i].y1 <= lowest )            {                ans += ( seg[i].y1 - seg[i].y2 );                lowest = seg[i].y2;            }            else if( seg[i].y1 > lowest )            {                if( seg[i].y2 < lowest )                {                    ans += ( -seg[i].y2 + lowest );                    lowest = seg[i].y2;                }                if( seg[i].y2 > lowest )                    ans += 0;            }        }        printf( "%.2lf\n", ans );    }    return 0;}


G题 , 树的性质, yy结论题, 因为之需要修复一个RPedge, 那么其减少的RPpath条数必然是该edge两边的2个非RPedge构成的分量的乘积, 先处理所有的非RPedge,用带权值的并查集维护连通分量和分量中点的个数。

typedef long long ll;const int maxn=200000+123;int rank[maxn], p[maxn];int find(int x){    if(x!=p[x])p[x]=find(p[x]);    return p[x];}void merge(int a, int b){    int fa=find(a), fb=find(b);    if(fa==fb)return ;    if(rank[fa]>rank[fb])p[fb]=fa, rank[fa]+=rank[fb];    else p[fa]=fb, rank[fb]+=rank[fa];    //if(rank[fa]==rank[fb])rank[fb]++;}struct Node{    int u, v;}edge[maxn];void init(int x){    for (int i=1; i<=x; ++i)    {        p[i]=i;        rank[i]=1;    }}int main(){    int n;    while (~scanf("%d", &n))    {        init(n);        int cnt=0;        for (int i=1; i<n; ++i)        {            int a, b, c; scanf("%d%d%d", &a, &b, &c);            if(c==1)            {                //printf("%d %d %d cnt===%d\n", a, b, c, cnt);                edge[cnt].u=a; edge[cnt].v=b;                cnt++;            }            else                merge(a, b);        }        ll ans=(ll)n*(ll)(n-1)/2;        for (int i=1; i<=n; ++i)        {            if(i==find(i))                ans-=(ll)rank[i]*(ll)(rank[i]-1)/2;        }        //printf("%lld  cnt==%d\n", ans, cnt);//        for (int i=1; i<=n; ++i)//        {//            printf("%d %d %d\n", i, rank[i], p[i]);//        }        ll tmp, maxt=0;        for (int i=0; i<cnt; ++i)        {            const int &a=edge[i].u;            const int &b=edge[i].v;            int fa=find(a), fb=find(b);            const ll ra=rank[fa];            const ll rb=rank[fb];            ll rc=ra+rb;            tmp=rc*(rc-1)/2-ra*(ra-1)/2-rb*(rb-1)/2;            //printf("tmp==%d\n", tmp);            maxt=max(tmp, maxt);        }        printf("%lld\n", ans-maxt);    }    return 0;}


J题 , 组合数学, 非降路径公式, 用DP也可以解




原创粉丝点击