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;
    }
  • 相关阅读:
    2018.7.26笔记(变量的数据类型,if语句)
    id(),is 和 ==的区别,编码和解
    2018.7.31笔记(列表的基本操作)
    阅读与感悟如何高效学习
    说说设计模式 单例模式
    简单说说Java知识点 多线程
    阅读与感悟联盟
    阅读与感悟非暴力沟通
    简单说说Java知识点 HashMap
    MySQL知识树存储引擎
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3068816.html
Copyright © 2011-2022 走看看