zoukankan      html  css  js  c++  java
  • 多校第一场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;
    }

     

  • 相关阅读:
    [转] KVM I/O slowness on RHEL 6
    QEMU KVM libvirt 手册(3)
    QEMU KVM libvirt手册(2): monitor
    QEMU KVM libvirt 手册(1): 安装
    CentOS7下JSP连接Mysql
    使用Tomcat搭建基于域名的虚拟机
    CentOS7下搭建Tomcat服务器
    Nginx在线服务状态下平滑升级或新增模块
    源码安装LNMP
    二进制包安装Mysql
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2964904.html
Copyright © 2011-2022 走看看