2013-5-17 训练赛总结

训练赛链接: http://openoj.awaysoft.com:8080/judge/contest/view.action?cid=424#overview

题目来源: The 10th Zhejiang Provincial Collegiate Programming Contest

 还是想吐嘈 ZOJ的题目描述,与模拟题的恶心程度........

A Applications

   背景是ACM集训队选拔,根据OJ题数,区域赛获奖,CF/TC排名, 还有个性别,  注意的地方是CF不满三场不计算.

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<string>
#include<map>
#include<algorithm>
using namespace std;


const int N = 1010;

bool isprime(int x){
    for(int i = 2; i*i <= x; i++)
        if( x%i == 0 ) return false;
    return true;
}
int n, m;
bool cmp(int a,int b){
    return a > b;
}

map< string, int > regional;
map< int, double > tiku;
const double esp = 1e-8;
int sign(double x){
    return x < -esp ? -1 : (x >esp);
}
struct Peason{
    string name;
    string team_name;
    string sex;
    double score;
    vector<int> problem;
    vector<int> cf;
    void read(){
        // init
        problem.clear(); cf.clear();
        char tmp[50];
        int oj_num, cf_num, x;    
        scanf("%s",tmp); name = tmp;
        scanf("%s",tmp); team_name = tmp;
        scanf("%s",tmp); sex = tmp;
        scanf("%d %d",&oj_num,&cf_num );    
        for(int i = 0; i < oj_num; i++){
            scanf("%d", &x);
            problem.push_back(x);
        }    
        for(int i = 0; i < cf_num; i++){
            scanf("%d", &x);
            cf.push_back(x);
        }    
    }
    void modify(){
        score = 0;    
        if( regional.count( team_name ) ){
            int d = regional[team_name];    
            if( d == 1 ) score += 36;
            else if( d == 2 ) score += 27;
            else if( d == 3 ) score += 18;
        }     
        for(int i = 0; i < (int)problem.size(); i++){
            int d = problem[i];    
            if( tiku.count(d) != 0 ) score += tiku[d];
            else if( isprime(d) ) score += 1;
            else score += 0.3;
        }     
        if( cf.size() >= 3 ){    
            sort( cf.begin(), cf.end(), cmp );    
            int r = cf[2];
            score += max( 0.0, (r-1200)/100. )*1.5;
        }    
        if( sex == "F" ) score += 33;

    }
    bool operator < (const Peason &tmp) const{
        if( sign(score-tmp.score) != 0 ){
            return sign(score-tmp.score) == 1;    
        }    
        else return name < tmp.name;    
    } 
}p[N];


void gao(){
    scanf("%d%d", &n, &m);
    // tiku info    
    int pro_n, x;
    scanf("%d", &pro_n);
    tiku.clear();
    for(int i = 0; i < pro_n; i++){
        scanf("%d", &x);
        tiku[x] = 2.5;
    }
    scanf("%d", &pro_n);
    for(int i = 0; i < pro_n; i++){
        scanf("%d", &x);
        tiku[x] = 1.5;
    }
    // regional    
    int team_num, rank;
    char str[N];
    scanf("%d", &team_num );
    regional.clear();    
    for(int i = 0; i < team_num; i++){
        scanf("%s %d", str, &rank );
        regional[str] = rank;
    }
    //peason
    for(int i = 0; i < n; i++)
        p[i].read(), p[i].modify();

    sort( p, p+n );
    for(int i = 0; i < m; i++)
        printf("%s %.3lf\n", p[i].name.c_str(), p[i].score );
}

int main(){ 
    int T;
    scanf("%d", &T);
    while( T-- ){
        gao();
    }
    return 0;
}
View Code

 

 

B Break Standard Weight

  已知a,b,枚举c, 取值范围 [1,a/2 ],  然后枚举天平左右放置情况,   再做一次(b,a)就好.

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<set>
#include<map>
#include<cmath>
#include<algorithm>
using namespace std;

const int N = 500;

bool vis[N];
int w[3];
int cao(int a,int b,int c){
    memset(w,0,sizeof(w));
    memset(vis,0,sizeof(vis));
    vis[0] = 1;
    int cnt = 0;    
    for(int i = 0; i <= 2; i++)
    {
        w[i] += a;
        for(int j = 0; j <= 2; j++)
        {
            w[j] += b;    
            for(int k = 0; k <= 2; k++)
            {
                w[k] += c;
                int t = abs( w[1]-w[2] );
                if( !vis[t] )
                    vis[t] = 1, cnt += 1;
                w[k] -= c;
            }
            w[j] -= b;    
        }
        w[i] -= a;    
    }
    return cnt;
}
int gao(int a,int b){
    int res = 0;
    for(int c = 1; c <= a/2; c++){
        // a, b, c
        res = max( res, cao( a-c, c, b ) );    
    } 
    return res;
}
int main(){
    int T;
    scanf("%d", &T);
    while( T-- ){
        int x, y;
        scanf("%d%d", &x,&y);
        printf("%d\n", max( gao(x,y), gao(y,x) ) );
    }
    return 0;
}
View Code

 

C Calculate Prime S

  首先通过枚举子集数量k, 得到Sn计算式子, Sn = \sum C( n-k+1, k ),  然后可看出来(输出前面一部分)是fibonacci数. 

  而对于 S 是prime的定义, 其实就是 Fibonacci素数,  对于fibonacci素数,这里可以得出两个性质:

    1.  从第5项(前五项为:1,1,2,3,5) 开始, 项数为素数,则Fi为Fib素数. 可通过 假定Fi%M, 然后由 Fk = 0, 则 F_(t*k) = 0, 得出.

    2.  Fibonacci数 Fi % M, 必有循环节, 且循环节长度是 O(M), 不太会证明.  -_-..据说要部分代数.

  然后解题思路是, 求出第k个S prime, 其实就是 第k个素数(前两项2,3,应该替换成3,4), 然后 Sn从P_k开始枚举, 当出现 Sn%x = 0, 则找到了对应的Sn.但是最终结果所求为 (Sn/x)%M,  可以转换成  Sn%(x*M).  然后最后再除以一个 X即可.  求 Fibonacci数 通过构造转置矩阵,快速幂求即可.

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

typedef long long LL;
const int N = (int)2e7+10;

int prime[N/10], p_num;
bool vis[N];
void GetPrime(){
    memset(vis,0,sizeof(vis));
    vis[1] = 1; p_num = 1;
    for(int i = 2; i < N; i++){
        if( !vis[i] ) prime[p_num++] = i;
        for(int j = 1; (j<p_num)&&(prime[j]*i<N); j++){
            vis[ prime[j]*i ] = 1;
            if( i%prime[j] == 0 ) break;
        }
    }
    prime[1] = 3, prime[2] = 4;
    // p_num = 1.2 * 10^6    
//    printf("%d\n", p_num );
}

struct Matrix{
    LL mat[2][2];
    void zero(){memset(mat,0,sizeof(mat));}
    void unit(){ zero(); mat[0][0]=mat[1][1]=1; }    
};
Matrix mult( Matrix A, Matrix B, int mod ){
    Matrix C; C.zero(); 
    for(int i = 0; i < 2; i++){
        for(int k = 0; k < 2; k++)
            for(int j = 0; j < 2; j++)
                C.mat[i][j] = (C.mat[i][j]+A.mat[i][k]*B.mat[k][j])%mod;
    }
    return C;
}
Matrix Pow( Matrix X, int n, int mod ){
    Matrix res; res.unit(); 
    while( n ){
        if( n&1 ) res = mult(res,X,mod);
        X = mult(X,X,mod);
        n >>= 1;
    }
    return res;
}


Matrix A, T;
void init_Matrix(){
    A.mat[0][0] = A.mat[1][0] = 1; A.mat[0][1] = A.mat[1][1] = 0;
    T.mat[0][0] = 0; T.mat[0][1] = T.mat[1][0] = T.mat[1][1] = 1;
}
void print( Matrix t ){
    for(int i = 0; i < 2; i++){
        for(int j = 0; j < 2; j++)
            printf("%lld ", A.mat[i][j] );
        puts("");
    }
}
void solve(){
    int k, x, m;
    scanf("%d%d%d", &k, &x, &m);
    int k_idx = prime[k], s_idx = k_idx;
//    printf("k_idx = %d\n", k_idx );    
    init_Matrix();    
    A = mult( Pow(T,k_idx-1,x), A, x ); 
//    print(A);    
    for( ;; s_idx++ ){
        if( A.mat[0][0] == 0 ) break;
        //printf("A.mat[0][0] = %lld, [1][0] = %lld\n", A.mat[0][0], A.mat[1][0] );    
        A = mult( T, A, x ); 
    }    
    //printf("s_idx = %d\n", s_idx );    
    init_Matrix();
    A = mult( Pow(T,s_idx-1,x*m), A, x*m );
    printf("%lld\n", A.mat[0][0]/x );
}
int main(){
    GetPrime();
    int T;
    scanf("%d", &T);
    while( T-- ){
        solve();    
    }
    return 0;
}
View Code

 

D Density of Power Network

  题目描述那副图好复杂.不过题意和图没多大关系. 统计不重复的边.然后除以顶点N即可. 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
using namespace std;

const int N = 550;

bool mp[N][N];
int a[N], b[N];


int main(){
    freopen("1.in", "r", stdin);

    int T;
    scanf("%d", &T);
    while( T-- ){
        int n, m;
        scanf("%d%d",&n,&m);
        memset(mp,0,sizeof(mp));
        for(int i = 0; i < m; i++)
            scanf("%d", &a[i]);
        for(int i = 0; i < m; i++)
            scanf("%d", &b[i]);
        for(int i = 0; i < m; i++)
            mp[ a[i] ][ b[i] ] = mp[ b[i] ][ a[i] ] = 1;
        int cnt = 0;    
        for(int i = 1; i <= n; i++)
            for(int j = i; j <= n; j++)
                cnt += mp[i][j];
        printf("%.3lf\n", 1.0*cnt/n );
    }
    return 0;
}
View Code

 

E Egg Painting

  计算几何只会水题版本...太神了不太会...

F Friends

  N才100, 枚举两个没关联的, 然后看其相同朋友是否大于等于K, 若是则连接.  要注意的是, 连接后还有可能给其他人造成影响.所以需要重复的搞. 第二组样例看的出来.

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
using namespace std;

const int N = 110;

bool mp[N][N];
vector<int> Q[N];
int n, m, k;

int main(){
    freopen("1.in","r",stdin);
    int T;
    scanf("%d", &T);
    while( T-- ){
        scanf("%d%d%d", &n,&m,&k);
        memset( mp, 0, sizeof(mp));
        for(int i = 0; i < n; i++) Q[i].clear();    
        for(int i = 0; i < m; i++){
            int a, b;
            scanf("%d%d",&a,&b);
            mp[a][b] = mp[b][a] = true;
            Q[a].push_back(b);
            Q[b].push_back(a);
        }
        int res = 0;    
        while( 1 ){    
        int cnt = 0;    
            for(int a = 0; a < n; a++){
            for(int b = a+1; b < n; b++){
                if( mp[a][b] == false){
                    int t = 0;    
                    for(int i = 0; i < (int)Q[a].size(); i++){
                        int c = Q[a][i];
                        if( mp[b][c] == true ) t++;
                    }            
                    if( t >= k ){
                        mp[a][b] = mp[b][a] = true;
                        Q[a].push_back(b);
                        Q[b].push_back(a);
                        cnt++;    
                    }    
                }    
            }    
        }    
            res += cnt;    
            if( cnt == 0 ) break;    
        }    
        printf("%d\n", res );    
    }
    return 0;
}
View Code

 

G Give Me Your Hand

  概率DP一直很渣.

H Hard to Play

  别想太复杂.. 可以证明, 因为次数累积, 则分数大的放后面连续必定最大,   反之则最小.

#include<cstdio>
int main(){
    int T;
    scanf("%d", &T);
    while( T-- ){
        int A, B, C;
        scanf("%d%d%d", &A,&B,&C);
        int res = 0, ans = 0;
        for(int i = 1, t = 0; i <= A+B+C; t++, i++ )
            if( i > B+C ) res += 300*( t*2+1 );    
            else if( i > C) res += 100*( t*2+1 );
            else res += 50*( t*2+1 );
        for(int i = 1, t = 0; i <= A+B+C; t++, i++ )
            if( i <= A ) ans += 300*( t*2+1 );    
            else if( i <= A+B ) ans += 100*( t*2+1 );
            else ans += 50*( t*2+1 );
        printf("%d %d\n", ans, res );    
    }
    return 0;
}
View Code

 

I In 7-bit

  神描述. 虽然我没看懂...但是队伍中有jian1573这样的大神.....

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <string>
#include <stdlib.h>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL Mod= 1e9+7;
const int M=3000050;
char s[M];
int T;
int main( )
{
    scanf("%d", &T);
    getchar();
    while(T--){
        gets(s);
        int len=strlen(s);
        if (len == 0) {
            puts("00");
            continue;
        }
        int t=len;
        while(t){
            int ans= (t&0x7f);
            t >>= 7;
            if( t>0 ) ans |= 0x80;
            printf("%02X",ans);
        }    
        for( int i=0; i<len; ++ i ){
            printf("%02X", s[i]);    
        }
        puts("");
    }
    return 0;
}
View Code

 

J Java Beans

  围成一圈,求连续M个最大值....N <= 100...M <= 100... 除了暴力我真心不知道还能干嘛.

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 210;
const int inf = 0x3f3f3f3f;
int n, m;
int a[N];

int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n,&m);
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        
        int res = 0;
        for(int i = 0; i < n; i++){
            int t = 0;    
            for(int j = 0; j < m; j++){
                t += a[ (i+j)%n ];
            }    
            res = max( res, t );    
        }
        printf("%d\n", res);    
    }
    return 0;
}
View Code

 

K Kindergarten Election

  正面贪心, 无法得到正确解.  变量过多, 通过枚举部分变量然后确定其他变量.  

  枚举 1获得票数x. 然后 处理其他票数大于X的,降至X-1,则必然只能加到1去. 1票数超过x则不合法, 若1的小于x,则再贿赂最小花费的人,加到x..然后求出最小的cost.即是最终答案.

有个地方我们没有处理, 就是当1获得x票,其他人都是x-1票.这个时候,因为1本身要投一票给别人. 可能会有其他N-1个都含有X-1票,这时候会发现1拿X票不一定赢, 其实简单推下就能发现这种情况是不存在的, 若存在, 则这时候有 x + (N-1)*(x-1) + 1 = N , 然后变换下得到  x = 2 - 2/N,  因为N>=3,  则 x必定为浮点数,而非整数. 所以此时的X是不存在的. 所以此情况无需考虑. 然后代码写起来就很短了.

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;

const int N = 200;
const int inf = 0x3f3f3f3f;
int f[N], c[N], d[N];
int n;
int tf[N], td[N];
bool vis[N];

int GetMax(){ // temp
    int t = -1;    
    for(int i = 2; i <= n; i++)
        t = max( t, td[i] );
    return t;
}
int update(int x){ // tmp_father and tmp_depth
    td[ tf[x] ]--;
    td[1]++;
    tf[x] = 1;
    return c[x];
}
int maintain(int tar){
    int cost = 0;    
    bool flag = false;        
    for(int i = 2; i <= n; i++){
        if( td[i] < tar-1 ) 
            flag = true;
    }
    if( flag ) return cost;
    else{
        int t = inf, pos;
        for(int i = 2; i <= n; i++){
            if( (td[ tf[i] ] == tar-1) && (t > c[i]) )
                t = c[i], pos = i;
        }
        cost += update(pos);        
        return cost;    
    }
}    
int cao(int tar){
    int cost = 0, k;
    for(int i = 1; i <= n; i++)
        td[i] = d[i], tf[i] = f[i];
    k = GetMax();
    while( k >= tar ){
        int t = inf, pos;
        for(int i = 2; i <= n; i++){
            if( (tf[i]!=1) && (td[tf[i]]>=tar) && (t>c[i]) )    
                    t = c[i], pos = i;
        }
        cost += update( pos );    
        k = GetMax();
    }    
    if( td[1] > tar ) return inf;
    else{
        while( td[1] < tar ){
            int t = inf, pos;
            for(int i = 2; i <= n; i++)
                if( (tf[i]!=1) && (t > c[i]) )
                    t = c[i], pos = i;
            cost += update(pos);
        }    
    //    cost += maintain( tar );        
        return cost;    
    }
}
int gao(){
    int res = inf;
    for(int i = 2; i <= n-1; i++){
        int t = cao(i);
    //    printf("i = %d, t = %d\n", i, t);
        res = min( res, t );
    }    
    return res;
}
int main(){
    int T;
    scanf("%d", &T);
    while( T-- ){
        scanf("%d", &n);
        memset( d, 0, sizeof(d));
        memset( c, 0, sizeof(c)); 
        for(int i = 2; i <= n; i++){
            scanf("%d", &f[i] );
            d[ f[i] ]++;
        }
        for(int i = 2; i <= n; i++){
            scanf("%d", &c[i] );    
        }    
        printf("%d\n", gao() );    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/yefeng1627/archive/2013/05/18/3085678.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值