多校第一场CSUST 个人解题报告

整个寒假+3月份 都在开发OJ,好久没写题解了。

 

第一题 Non-negative Partial Sums

  解法一:

    预处理前缀和 sum[N] , 对于通用序列 ( a(i+1), a(i+2), ... a(n), a(1) ... a(i) ),将其分为 ( a(i+1) ... a(n) ), ( a(1)...a(i) )\

两段, 此循环是以 a(i+1) 为起始的序列, 若其所有前缀和要满足条件,则

    Min{ sum(1)...sum(i) } + sum(n)-sum(i+1) >= 0

    MIN{ sum(i+1)...sum(n) } - sum(i) >= 0

  解法二: (解题报告所给)

    将序列扩成2倍,解决循环问题, 然后预处理前缀和后,从n往1扫,在每个位置维护之后的n个值,

这里需要使用队列优化,但是不能用系统STL的priority_queue 会出TLE。

  这里给出解法一的代码:

View Code
#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<iostream>

#include<algorithm>

#include<math.h>



#define MIN(a,b) (a)<(b)?(a):(b)

const int N = 2000010;



int a[N], b[N], left[N], right[N];

int n;



int main(){

    

    while( scanf("%d", &n), n )

    {

        a[0]=b[0]=left[0]=right[0];



        for(int i = 1; i <= n; i++) scanf("%d", &a[i] );

        for(int i = 1; i <= n; i++) b[i] = b[i-1]+a[i]; 

        left[1] = b[1];

        right[n] = b[n];

        for(int i = 2; i <= n; i++) 

            left[i] = MIN( left[i-1], b[i] );

        for(int i = n-1; i >= 1; i-- )

            right[i] = MIN( right[i+1], b[i] );



        int res = 0;

        for(int i = n; i >= 1; i-- ){

            int tmp = MIN( right[i]-b[i-1] , left[i-1]+(b[n]-b[i-1]) );

            if( tmp >= 0 ) res++;

        }

        printf("%d\n", res );    

    }

    return 0;

}

 

第二题 拯救猫咪

  没写,解题报告上说是模拟题,一秒一秒模拟能够过。

 

第三题 兔纸的难题

  比赛时,以为是规律题,各种推,后果很惨淡~~

  状态 dp( i, j ) 表示外面还有 i只兔子,栈中还有 j只兔子时的方案数。

   从外面跳入一只兔子到栈中,只会导致两种情况: 一是消去3个,二是增加1个 

  所以转移方程为:

    dp( i, j ) = dp( i+1, j-1 ) + dp( i+1, j+2 )

  另外,当栈中剩2只兔子时,颜色是可以不限定的,其他情况是限定的

  所以有

    dp( i, j ) = dp( i+1, j-1 ) + 2*dp( i+1, j+2 )

  代码实现时,初始化 只有dp( n, 0 ) = 1 ,其他都为0 ,注意,对于任意i 要枚举 J

解题代码

View Code
#include<stdio.h>

#include<string.h>

#include<stdlib.h>

 

const int N = 1010;

const int mod = 1e9+7;

 

int dp[N][N];

int n;

 

int main()

{

    while( scanf("%d", &n) != EOF)

    {

        if( n == -1 ) break;

        if( n%3 != 0 ){

            printf("0\n");

            continue;   

        }

        memset( dp, 0, sizeof( dp ) );

        dp[n][0] = 1;

        for(int i = n-1; i >= 0; i-- )

        {

            for(int j = 0; j <= n; j++ )

            {

                if( j-1 >= 0 )

                    dp[i][j-1] = (dp[i][j-1]+dp[i+1][j])%mod;

                if( j+2 <= n ){

                    dp[i][j+2] = (dp[i][j+2]+dp[i+1][j])%mod;

                    if( j == 0 )

                        dp[i][j+2] = (dp[i][j+2]+dp[i+1][j])%mod;   

                }

            }   

        }   

        printf("%d\n", dp[0][0] );

    }

    return 0;   

}

 

第四题 二哥的内存

  行列相互独立,使用数组记录当前行原本是哪行即可。列一样。

View Code
#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<algorithm>

#include<map>

using namespace std;



const int N = 1e5+10;



map<int, int> mp[N];

int row[N], col[N];

int n, m;



int main()

{

    while( scanf("%d", &n) != EOF )

    {

        if( n == -1 ) break;

        for(int i = 0; i < N; i++)

        {

            row[i] = col[i] = i;            

            mp[i].clear();        

        }        

        for(int i = 0; i < n; i++)

        {

            int a, b, c;

            scanf("%d%d%d", &a,&b,&c);

            mp[a][b] = c;

        }

        

        scanf("%d", &m);

        int tmp;    

        for(int i = 0; i < m; i++)

        {

            int op, x, y;

            scanf("%d%d%d",&op,&x,&y);

            switch( op ){

                case 0:

                    tmp = row[x]; row[x] = row[y]; row[y] = tmp;    

                    break;

                case 1:

                    tmp = col[x]; col[x] = col[y]; col[y] = tmp;    

                    break;    

                default:

                    x = row[x]; y = col[y];    

                    if(  mp[x].count(y) == 0 ){

                        printf("0\n");

                    }    

                    else printf("%d\n", mp[x][y] );    

            }

        }

    }

    return 0;

}

 

第五题 Wally World

  简单几何, 判断线段相交

View Code
#include <iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<math.h>



using namespace std;

typedef double PointType;

#define MIN(a,b) (a)<(b)?(a):(b)



struct point

{

    PointType x,y;

    void input(){ scanf("%lf%lf", &x,&y); }

};

PointType Direction(point pi,point pj,point pk) //判断向量PiPj在向量PiPk的顺逆时针方向 +顺-逆0共线

{

    return (pj.x-pi.x)*(pk.y-pi.y)-(pk.x-pi.x)*(pj.y-pi.y);

}

bool On_Segment(point pi,point pj,point pk)

{

    if(pk.x>=min(pi.x,pj.x)&&pk.x<=max(pi.x,pj.x)&&pk.y>=min(pi.y,pj.y)&&pk.y<=max(pi.y,pj.y))

    return 1;

    return 0;

}

bool Segment_Intersect(point p1,point p2,point p3,point p4)

{

    PointType d1=Direction(p3,p4,p1),d2=Direction(p3,p4,p2),d3=Direction(p1,p2,p3),d4=Direction(p1,p2,p4);

    if(((d1>0&&d2<0)||(d1<0&&d2>0))&&((d3>0&&d4<0)||(d3<0&&d4>0)))

    return 1;

    if(d1==0&&On_Segment(p3,p4,p1))

    return 1;

    if(d2==0&&On_Segment(p3,p4,p2))

    return 1;

    if(d3==0&&On_Segment(p1,p2,p3))

    return 1;

    if(d4==0&&On_Segment(p1,p2,p4))

    return 1;

    return 0;

}

double dis( point p1, point p2 ){

    return sqrt( (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y) );

} 

int main(){

    point p1, p2, p3, p4;

    int x1, y1, x2, y2, Case = 1;

    while( scanf("%d%d%d%d", &x1, &y1, &x2, &y2) != EOF)

    {

        if( (x1==0)&&(y1==0)&&(x2==0)&&(y2==0) ) break;

        p1.x = x1, p1.y = y1;

        p2.x = x2, p2.y = y2;

        p3.input(); p4.input();



        double res;

        if( Segment_Intersect( p1, p2, p3, p4 ) ){

            res = MIN( dis(p1,p3)+dis(p2,p3), dis(p1,p4)+dis(p2,p4) ); 

        }    

        else{

        res = dis(p1,p2);

        }    

        printf("Case %d: ", Case++ );

        printf("%.3lf\n", res/2. );

    }

    return 0;

}

第六题 小云过生日

  贪心,考虑间隔

View Code
#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<algorithm>

#include<queue>

using namespace std;



const int N = 200008;



int a[N], Q[N];

int m, n, s;





int main()

{

    while( scanf("%d%d%d", &m,&n,&s), n+m+s )

    {

        for(int i = 0; i < s; i++)

            scanf("%d", &a[i] );

        sort( a, a+s );

        s = unique( a, a+s ) - a;



        int cnt = 0;



        for(int i = 0; i < s-1; i++)

        {

            int t = a[i+1]-a[i]-1;

            if( t  ) Q[cnt++] = t;

        }

        if( m >= (cnt+1) ) printf("%d\n", s );

        else{

            sort( Q, Q+cnt );    

            int tmp = 0;    

            for(int i = 0; i < ((cnt+1)-m); i++)

                tmp += Q[i];

            printf("%d\n", tmp+s );

        }    

    }

    

    return 0;

}

第七题 数学

  预处理前缀乘积和后缀乘积,然后避免除法,就可以使用同余定理了。

View Code
#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<math.h>



typedef long long LL;

const int mod = 1e9+7;

const int N = 1e5+10;





LL A[N],B[N], left[N],right[N];

int n;



int main()

{

    while( scanf("%d", &n), n )

    {

        left[0] = right[n+1] = 1;



        for(int i = 1; i <= n; i++)

            scanf("%lld", &A[i] );

        for(int i = 1; i <= n; i++)

        {

            left[i] = left[i-1]*A[i]%mod;

            right[n+1-i] = right[n+2-i]*A[n+1-i]%mod;

        }            

        for(int i = 1; i <= n; i++)

            B[i] = left[i-1]*right[i+1]%mod;

        for(int i = 1; i <= n; i++)

            printf( (i==1)?"%lld":" %lld", B[i] );

        puts("");

    }

    return 0;

}

第八题 跳格子

  考虑要走固定步长到终点,其实只有到终点后还剩余步长时,如何处理。 奇偶判定即可,因为

从当前点走出去再走回来必定是偶数步。 所以BFS时可以标记,这样就不会超内存了。

View Code
#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<queue>

#include<iostream>

#include<algorithm>



using namespace std;



const int N = 10;



int n, m, s;

int dir[4][2] = { {0,-1},{0,1},{1,0},{-1,0} };

bool vis[N][N];



char mp[N][N];



struct node{

    int x, y, step;

}st,ed,cur,nxt;



queue<node> Q;



bool legal( int x, int y )

{

    if( (x>=0)&&(x<n)&&(y>=0)&&(y<m) )

        return true;

    return false;

}

bool BFS(){

    

    while( !Q.empty() ) Q.pop();

    memset( vis, 0, sizeof(vis) );



//    vis[st.x][st.y] = true;

    Q.push( st );



    while( !Q.empty() ){

        cur = Q.front(); Q.pop();

        if( (mp[ cur.x ][ cur.y ] == 'D') && cur.step == s ) return true;



        for(int i = 0; i < 4; i++)

        {

            nxt.x = cur.x+dir[i][0];

            nxt.y = cur.y+dir[i][1];

            if( legal( nxt.x, nxt.y ) && (!vis[nxt.x][nxt.y]) 

                    && (cur.step < s) && (mp[nxt.x][nxt.y] != 'X') ){

                nxt.step = cur.step+1;

                vis[nxt.x][nxt.y] = true;

                if( mp[nxt.x][nxt.y] == 'D' ){

                    if( (nxt.step==s) || !((s-nxt.step)&1) ) return true;

                    else    return false;

                }

                Q.push( nxt );

            }

        }

    }

    return false;

}

int main()

{

    while( scanf("%d%d%d",&n,&m,&s) != EOF )

    {

        if( n+m+s == 0 ) break;



        for(int i = 0; i < n; i++)

            scanf("%s", mp[i] );

        for(int i = 0; i < n; i++)

            for(int j = 0; j < m; j++)

            {

                if( mp[i][j] == 'S' )

                    st.x = i, st.y = j, st.step = 0;                    

                if( mp[i][j] == 'D' )

                    ed.x = i, ed.y = j, ed.step = 0;    

            }

        bool flag = BFS();

        puts( flag ? "YES" : "NO" );



    }

    return 0;

}

 

 

你可能感兴趣的:(个人)