zoukankan      html  css  js  c++  java
  • 201357 训练赛总结

    题目来源 The 13th Zhejiang University Programming Contest

    链接: http://openoj.awaysoft.com:8080/judge/contest/view.action?cid=421#overview

    A - Alien's Organ

    题意: 事件出现平均概率为a, 问出现次数小于等于N的概率

    解法:  泊松分布, P(X=k)=\frac{e^{-\lambda}\lambda^k}{k!} ,跟着公式算就好.

    View Code
    // p(k) = e^(-ave) * ave^k / k!
    #include<cstdio>
    #include<cmath>
    
    int main(){
        double ave;
        int T, n;
        scanf("%d", &T);    
        while( T-- ){
            scanf("%d %lf", &n,&ave);    
            double p = 0, a = 1, b = 1;
            for(int i = 0; i <= n; i++){
                p += exp(-ave)*a/b;
                a *= ave;
                b *= (i+1);
            }
            printf("%.3lf\n", p );    
        }
        return 0;
    }

    B - Bad-written Number

    题意:  LED灯表示一个数字,用了3*3行,   现在有N个数字, 前一个数字的第三列与后一个数字的第一列重叠,问可能出现合法的方案有多少.

    解法:  状态压缩DP,  dp( i, j ), 表示 前i个数, 最后一个数的第三列状态j, 合法的方案数量. 转移方程为:  

      dp( i+1,  a[k][2] )  += dp( i, j ),  其中 a[k][ 0,1,2 ] ,表示数字 k,的第1,2,3列状态. 

    View Code
    #include<cstdlib>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<string>
    #include<map>
    using namespace std;
    typedef long long LL;
    
    const int N = 20100;
    const LL mod = (LL)1e9+7;
    
    char str[3][N];
    
    const char* tar[] = {
    " _ | ||_|",
    "     |  |",
    " _  _||_ ",
    " _  _| _|",
    "   |_|  |",
    " _ |_  _|",
    " _ |_ |_|",
    " _   |  |",
    " _ |_||_|",
    " _ |_| _|"
    };
    int a[10][3], b[N], n;
    LL dp[N][4];
    
    void pre(){
        memset( a, 0, sizeof(a) );    
        for(int i = 0; i <= 9; i++)    
            for(int j = 0; j < 3; j++)
                for(int k = 0; k < 3; k++)
                    //a[i][j] |= (tar[i][j+3*k] != ' ') << k;
                    a[i][j] = (a[i][j]<<1) | (tar[i][j+3*k] != ' ');
        //for(int i = 0; i < 10; i++)
        //    printf("%d: %d, %d, %d\n", i, a[i][0], a[i][1], a[i][2] );
    
    }
    void init(){
        memset( str, 0, sizeof(str));
        memset( b, 0 , sizeof(b));    
            
        for(int i = 0; i < 3; i++){
            gets( str[i] );    
            for(int j = strlen(str[i]); j < 2*n+1; j++)
                str[i][j] = ' ';
        }
        for(int j = 0; j < 3; j++)
            for(int i = 0; i < 2*n+1; i++)
                //b[i] |= (str[j][i] != ' ') << j;    
                b[i] = (b[i]<<1) | (str[j][i]!=' ');
    }
    
    void solve(){
        memset( dp, 0, sizeof(dp));
        dp[0][0] = 1;    
        for(int i = 0; i < n; i++){
            int idx = 2*i;    
            for(int j = 0; j < 4; j++){
                if( dp[i][j] == 0 ) continue;    
                for(int k = 0; k < 10; k++){
                    if( (j | a[k][0]) != b[idx] ) continue;
                    if( a[k][1] != b[idx+1] ) continue;
                    if( (a[k][2] & b[idx+2]) != a[k][2] ) continue;
                    dp[i+1][ a[k][2] ] += dp[i][j];
                    dp[i+1][ a[k][2] ] %= mod;    
                }    
            }        
        }    
        printf("%lld\n", dp[n][ b[2*n] ]);
    }
    int main(){
        freopen("2.in","r",stdin);
        pre();
        int T;
        scanf("%d", &T);
        while( T-- ){
            scanf("%d", &n); getchar();
            init();
            solve();    
        }
        return 0;
    }

    C - Carrot Fantasy

    题意: 很复杂- - ...和塔防一样.的模拟题.

    解法: 按照时间模拟..不过好恶心.

    D - Dakar Rally

    题意: N段路, 每段路有个长度Li, 与单位耗油量ai,路段开始有个加油站,加油单价pi, 问按顺序走完所有路,最小花费.

    解法: 贪心,  经过每一个加油站, 把油全部加满,  并利用单调队列保存, 这个油的数量与单价, 加油时,替换掉贵的, 使用时,从价格低的开始使用.

    计算花费, 只算真正使用过的油.

    View Code
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    const int N = (int)1e5+100;
    
    int n; LL k;
    struct TMP{
        LL a, b, c;
        void input(){
            scanf("%lld%lld%lld",&a,&b,&c);    
        }
    }route[N];
    
    struct node{
        LL gap, c;            
    }Q[N<<1], pre;
    
    bool init(){
        for(int i = 0; i < n; i++)
            route[i].input();
        for(int i = 0; i < n; i++)
            if( 1LL*route[i].a*route[i].b > k ) return false;
        return true;
    }
    void solve(){
        LL res = 0, s;
        int l = 0, r = 0; 
        for(int i = 0; i < n; i++){
            // clear and full the gap.
            while( (r>l) && (Q[r-1].c > route[i].c) ) r--;
            s = 0; 
            for(int j = l; j < r; j++) s += Q[j].gap;
            pre.c = route[i].c; pre.gap = k-s;    
            Q[r++] = pre;    
            // use the gap from the cheapest.
            s = 1LL*route[i].a*route[i].b;
            while( (l<r) && (Q[l].gap <= s) ){
                res += Q[l].gap*Q[l].c;
                s -= Q[l++].gap; 
            }
            if( s > 0 ){
                res += s*Q[l].c;    
                Q[l].gap -= s;    
            }    
        }
        printf("%lld\n", res);
    }
    int main(){
        int T;
        scanf("%d", &T);
        while( T-- ){
            scanf("%d%lld", &n,&k);
            if( init() ) solve();
            else printf("Impossible\n");
        }
        return 0;
    }

    E - Ever Dream

    题意: 给N行字符, 然后统计单词出现频率. 输出频率大于1的, 最长单词,当有多个,则输出倒数第二个.

    解法: 跟着模拟即可. 用STL来写.比较方便. 对于输入的处理, 将非英文字符全部换成空格,再利用strtok来分割.这样就蛮方便了.

    View Code
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<map>
    #include<vector>
    #include<algorithm>
    using namespace std;
    
    map<string,int> mp;
    
    
    bool isletter( char ch ){
        if( ( (ch>='a')&&(ch<='z') ) || ( (ch>='A')&&(ch<='Z') ) )
            return true;
        return false;
    }
    bool Upletter( char ch ){
        if( (ch>='A') && (ch<='Z') )
            return true;
        return false;
    }
    
    struct node{
        string s;
        int len;
        bool operator < (const node &tmp) const{
            return (len>tmp.len)||((len==tmp.len)&&(s<tmp.s));    
        }
    }nxt;
    vector< node > Q[110];
    void solve(){
        int n;
        char str[110];
        scanf("%d", &n); getchar();
        mp.clear();
        for(int i = 0; i < n; i++){
            memset(str, 0, sizeof(str));    
            gets( str );
            int L = strlen(str);
            for(int i = 0; str[i]; i++){
                if( isletter( str[i] ) ){
                    if( Upletter( str[i] ) )
                        str[i] += 32;
                }
                else    str[i] = ' ';    
            }
            char *p = strtok( str, " " );
            while( p ){
                if( mp.count(p) == 0 ) mp[p] = 1;
                else    mp[p] += 1;
                p = strtok( NULL, " " );
            }    
        }
        for(int i = 0; i <= 100; i++)
            Q[i].clear();
        for( map<string,int>::iterator it = mp.begin(); it != mp.end(); it++ ){
            nxt.s = it->first;
            nxt.len = (it->first).size();
            Q[ it->second ].push_back( nxt );
        }
        for(int i = 0; i <= 100; i++)    
            sort( Q[i].begin(), Q[i].end() );
        bool flag = true;    
        for(int i = 100; i > 1; i-- ){
            if( (int)Q[i].size() == 0 ) continue;    
        /*    printf("len = %d, size = %d\n", i, Q[i].size() );    
            for(int j = 0; j < (int)Q[i].size(); j++ ){
                printf("%s ", Q[i][j].s.c_str() );    
            } puts("");    
        */    
            int cur = 1;    
            for(int j = 1; j < (int)Q[i].size(); j++ ){
                if( Q[i][j].len == Q[i][j-1].len ) cur++;
                else break;
            }    
            if( flag ) flag = false;
            else printf(" ");
            if( cur == 1 ) printf("%s", Q[i][0].s.c_str() );
            else printf("%s", Q[i][cur-2].s.c_str() );
        }
        puts("");
    }
    int main(){
        freopen("1.in","r",stdin);
        int T;
        scanf("%d", &T);
        while( T-- ){
            solve();    
        }
        return 0; 
    }

    F - Fawful's Revenge

    据说此题很神....

    G - Gibonacci number

    题意: G(i) = G(i-1) + G(i-2), 现在给出 G(0) = 1,  G(i) , i, 让求 G(j), 当 G(1) > 0 , 否则输出 -1.

    解法:  G(i) = F(i-1)*G(1) + F(i-2) , 带入计算即可. 注意判定是否合法.

    View Code
    #include<cstdio>
    
    typedef long long LL;
    
    LL f[25], G[25];
    
    int main(){
        f[0] =  f[1] = 1;
        for(int i = 2; i <= 20; i++) f[i] = f[i-1]+f[i-2]; 
        int T, i, gi, j;
        scanf("%d", &T);
        while( T-- ){
            scanf("%d%d%d", &i,&gi,&j); // i, Gi, j
            
            if( i == 1 ){
                if( gi < 1 ){
                    printf("-1\n"); continue;    
                }    
                if( j == 1 ) printf("%d\n", gi );
                else    printf("%lld\n", f[j-1]*gi+f[j-2] );
            }
            else{
                if( (gi-f[i-2])%f[i-1] != 0 ) printf("-1\n");
                else{
                    LL g1 = (gi-f[i-2])/f[i-1];
                    if( g1 < 1 ){
                        printf("-1\n"); continue;    
                    }    
                    if( j == 1 ) printf("%lld\n", g1);
                    else printf("%lld\n", f[j-1]*g1+f[j-2] );    
                }
            }    
        }
        return 0;
    }

    H - Happy Programming Contest

    题意:  N个题目,每个题目有个完成时间,有个价值,现在给定时间T,求最大完成数量,最小完成时间,最大价值.

    解法: 01背包, 只是多了点条件

    View Code
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N = 1010;
    
    int num[55][1010], dp[55][1100], time[55][1100], sum[55][1100];
    int n, T;
    
    struct node{
        int t, c;
        bool operator < (const node &tmp)const{
            return (t<tmp.t)||(t==tmp.t&&c>tmp.c);        
        }
    }p[55];
    
    int main(){
        int T, t;
        scanf("%d", &t);
        while( t-- ){
            scanf("%d%d", &T, &n);
            for(int i = 1; i <= n; i++)
                scanf("%d", &p[i].t);
            for(int i = 1; i <= n; i++)
                scanf("%d", &p[i].c);
            sort( p+1, p+n+1 );
            memset( dp, 0, sizeof(dp));
            memset( num, 0, sizeof(num));
            memset( sum, 0, sizeof(sum));    
            for(int i = 1; i <= n; i++){
                for(int j = 0; j <= T; j++){
                    // dp[i][j] = max( dp[i-1][j], dp[i-1][j-p[i].t]+p[i].c );
                    dp[i][j] = dp[i-1][j]; num[i][j] = num[i-1][j];
                    sum[i][j] = sum[i-1][j];    
                    if( j >= p[i].t ){
                        if( dp[i][j] <= (dp[i-1][j-p[i].t]+p[i].c) ){
                            if( dp[i][j] < dp[i-1][j-p[i].t]+p[i].c ){
                                dp[i][j] = dp[i-1][j-p[i].t]+p[i].c;
                                num[i][j] = num[i-1][j-p[i].t]+1;
                                sum[i][j] = sum[i-1][j-p[i].t] + j;      
                            }    
                            else if( num[i][j] <= num[i-1][j-p[i].t]+1 ){
                                 if( num[i][j] < num[i-1][j-p[i].t]+1 ){    
                                    num[i][j] = num[i-1][j-p[i].t]+1;
                                    sum[i][j] = sum[i-1][j-p[i].t] + j;    
                                 }    
                                 else if( sum[i][j] > sum[i-1][j-p[i].t] + j ){
                                     sum[i][j] = sum[i-1][j-p[i].t] + j;
                                    }    
                            }    
                        }
                    }    
                }
            }
            int pc = 0, pn = 0, pt = 0;
            for(int i = 0; i <= T; i++){
                if( pc < dp[n][i] ){
                    pc = dp[n][i];pn = num[n][i];pt = sum[n][i];
                }    
                else if( pc == dp[n][i] ){
                    if( pn < num[n][i] )
                        pn = num[n][i], pt = sum[n][i];    
                    else if( pt > sum[n][i] )
                        pt = sum[n][i];
                }        
            }
            printf("%d %d %d\n", pc, pn, pt );    
        }
        return 0;
    }

    I - I am Nexus Master!

    题意: 论坛有10个等级, 一个用户的等级评定,通过使用 注册时间,下载量,上传量, 上传/下载 比例来恒定.给你当前一个用户的信息,然后反馈其等级.

    解法:  顺着模拟即可.  大致是 先判定是否直接降级到0, 否则再判定是否降级, 若没有 再判定是否升级. 

    View Code
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const double esp = 1e-8;
    
    const string tar[] = {
        "Peasant",         // 0
        "User",             // 1 
        "Power_User",     // 2
        "Elite_User",    // 3
        "Crazy_User",    // 4
        "Insane_User",   // 5
        "Veteran_User",     // 6
        "Extreme_User",  // 7
        "Ultimate_User", // 8
        "Nexus_Master"   // 9
    };
    double A[10]={
    0,0,50,120,300,500,750,1024,1.5*1024,3*1024
    };
    double B[10]={
    0,0,1.05,1.55,2.05,2.55,3.05,3.55,4.05,4.55    
    };
    int C[10]={
    0,0,4,8,15,25,40,60,80,100
    };
    int sign(double x){
        return x<-esp?-1:(x>esp);
    }
    string s;
    int week, cur;
    double down, up;
    void input(){
        char tmp[20];
        scanf("%s %d %lf %lf", tmp, &week, &down, &up );
        s = tmp;
        for(int i = 0; i < 10; i++) 
            if( s == tar[i] ){
                cur = i; break;    
            }
    }
    bool Clear(){
        if( (sign(down-50 ) >= 0) && (sign(up-0.4*down) < 0) ) return true;
        if( (sign(down-100) >= 0) && (sign(up-0.5*down) < 0) ) return true; 
        if( (sign(down-200) >= 0) && (sign(up-0.6*down) < 0) ) return true; 
        if( (sign(down-400) >= 0) && (sign(up-0.7*down) < 0) ) return true; 
        if( (sign(down-800) >= 0) && (sign(up-0.8*down) < 0) ) return true; 
        return false;    
    }
    bool Down(){ //可连续下降
        bool flag =  false;
        while( (cur>1) && (sign(up - down*(B[cur]-0.1)) < 0) )
            cur -= 1, flag = true;
        return flag;
    }
    void Up(){ //若降级过,则必定不可能升级
        int x = 9;    
        for(int x = 9; x > cur; x-- ){
            if( (x>cur) && (week>=C[x]) && (sign(down-A[x])>=0)
                && (sign(up-down*B[x])>=0) ){
                cur = x; break;
            }    
        }
    }
    
    int main(){
        int T;
        scanf("%d", &T);
        while( T-- ){
            input(); 
            if( Clear() ) printf("%s\n", tar[0].c_str() );
            else{
                if( Down() == false ) Up();
                printf("%s\n", tar[cur].c_str() );
            }
        }
        return 0;
    }
  • 相关阅读:
    win7下的vxworks总结
    ubuntu 无法获得锁 /var/lib/dpkg/lock
    项目中用到了的一些批处理文件
    win7下安装 WINDRIVER.TORNADO.V2.2.FOR.ARM
    使用opencv统计视频库的总时长
    January 05th, 2018 Week 01st Friday
    January 04th, 2018 Week 01st Thursday
    January 03rd, 2018 Week 01st Wednesday
    January 02nd, 2018 Week 01st Tuesday
    January 01st, 2018 Week 01st Monday
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3068816.html
Copyright © 2011-2022 走看看