暑期集训-German Collegiate Programming Contest 2015 解题报告

43 篇文章 1 订阅
26 篇文章 0 订阅

B. Bounty Hunter II
题目链接:https://nanti.jisuanke.com/t/18486
题意:给定几个点及其边,问派几个人可以遍历这些点,前提是每个点只能一个人走。
更为清晰的说法是题解中的:

Given a DAG with N nodes find the minimum number of vertex-disjoint
paths to cover each vertex.

思路:没想到竟然是二分图匹配。。。
Code:

#include <bits/stdc++.h>
using namespace std ;
const int AX = 1e3+6;
int G[AX][AX];
int used[AX];
int link[AX];
int n ;

bool dfs( int u ){
    for( int i = 0 ; i < n ; i++ ){
        if( G[u][i] && !used[i] ){
            used[i] = 1;
            if( link[i] == -1 || dfs( link[i] ) ){
                link[i] = u ;
                return true;
            }
        }
    }
    return false;
}

int xyl(){
    int res = 0 ;
    memset( link , -1 , sizeof(link) );
    int u ;
    for( u = 0 ; u < n ; u++ ){
        memset(  used , 0 , sizeof(used) );
        if( dfs(u) ) res ++;
    }
    return res;
}


int main(){
    scanf("%d",&n);
    int x , y ;
    for( int i = 0 ; i < n ; i++ ){
        scanf("%d",&x);
        for( int j = 0 ; j < x ; j++ ){
            scanf("%d",&y);
            G[i][y] = 1 ;
        }   
    }
    int ans = xyl();
    /*for( int i = 0 ; i < n ; i++ ){
        cout << "link[ " << i << " ] " << link[i] << endl;
    }*/
    printf("%d\n",n-ans);
    return 0 ;
}

E. Change of Scenery

题目链接:https://nanti.jisuanke.com/t/28394
题意:给出一个最短路及其各点和边,问有没有其他最短路。(题意开始错误理解成必须经过给定的节点。。然后以为dp。。)
思路:给的最短路没有用,直接求是否有两条以上最短路即可。用的是队列优化的dijstra算法,加一个每个点的路径记录次数的数组。
Code:


#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 1e4+666;
typedef pair<int,int> P ;
std::vector<P> G[AX];
int dis[AX];
int vis[AX];
int num_road[AX];
void dijstra(){
    priority_queue<P,vector<P>,greater<P> >q ;
    q.push(P(0,1));
    dis[1] = 0 ; 
    num_road[1] = 1 ;
    while( !q.empty() ){
        int u = q.top().second;
        int val = q.top().first;
        q.pop();
        if( vis[u] ) continue;
        vis[u] = 1 ;

        if( val > dis[u] ) continue;
        for( int i = 0 ; i < (int)G[u].size() ; i++ ){
            int v = G[u][i].first;
            int w = G[u][i].second;
            if( dis[v] > val + w ){
                dis[v] = val + w ;
                num_road[v] = num_road[u] ;
                q.push( P( dis[v] , v ) );
            }else if( dis[v] == val + w ){
                num_road[v] = 2  ;
            }
        }
    }
}

int main(){
    int n , m , k ;
    scanf("%d%d%d",&n,&m,&k);
    int x , y , z ;
    memset( dis , INF, sizeof(dis) );
    memset( num_road , 0 , sizeof(num_road ));
    memset( vis , 0 , sizeof(vis) ) ;
    for( int i = 0 ; i < k ; i++ ) scanf("%d",&x);
    for( int i = 0 ; i < m ; i++ ){
        scanf("%d%d%d",&x,&y,&z);
        G[x].push_back(P(y,z));
        G[y].push_back(P(x,z));
    }

    dijstra();
    if( num_road[n] > 1 ) printf("yes\n");
    else printf("no\n");
    return 0;
}




F. Divisions
题目链接:https://nanti.jisuanke.com/t/28395
题意:给出一个数(<1e16)输出因子个数
思路:因子个数就是对合数分解质因数,每个质因数的次方数加1,相乘。
数据过大用pollard rho算法和米勒拉宾素数测试。
Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdlib>
#define LL long long 
using namespace std;
const int S = 10;

LL mult( LL a , LL b , LL c ) {
    a %= c ;
    b %= c ;
    LL ret = 0;
    while( b ){
        if( b & 1 ){
            ret = ( ret + a ) % c ; 
        }
        b >>= 1 ;
        a <<= 1 ;
        if( a >= c ) a %= c ;
    }
    return ret;
}

LL quick( LL a , LL b , LL m ){
    LL res = 1;
    while( b ){
        if( b & 1 ){
            res = mult( res , a , m );
        }
        b >>= 1 ;
        a = mult( a , a , m ) % m ;
    }
    return res ;
}

bool check( LL a, LL n , LL x , LL t ){
    LL ret = quick( a , x , n );
    LL last = ret ;
    for( int i = 1 ; i <= t ; i++ ){
        ret = mult( ret , ret , n ) ;
        if( ret == 1 && last != 1 && last != n - 1 ) return true;
        last = ret ;
    }
    if( ret != 1 ) return true ;
    return false;
}

bool Miller_Rabin( LL n ){
    if( n < 2  ) return false;
    if( n == 2 ) return true; 
    if( !( n & 1 ) ) return false;
    LL x = n - 1;
    LL t = 0 ;
    while( !(x & 1) ){
        x >>= 1;
        t ++ ;
    }
    srand(time(NULL));
    for( int i = 0 ; i < S ; i++ ){
        LL a = rand() % ( n - 1 ) + 1;
        if( check( a , n , x , t ) ) return false;
    }
    return true;
}

LL factor[100];
int tot ;
LL gcd( LL a , LL b){
    if( !a ) return 1;
    if( a < 0 ) return gcd( -a , b );
    while( b ){
        LL t = a % b ;
        a = b ;
        b = t ;
    }
    return a;
}

LL pollard_rho( LL x , LL c ){
    LL i = 1 , k = 2 ;
    srand(time(NULL));
    LL x0 = rand() % (x-1) + 1 ;
    LL y = x0;
    while(1){

        i ++;
        x0 = ( mult( x0 , x0 , x ) + c ) % x;
        LL d = gcd( y - x0 , x );
        if( d != 1 && d != x ) return d;
        if( y == x0 ) return x;
        if( i == k ){
            y = x0 ;
            k += k;
        }
    }
}

void findfac( LL n , int k ){
    if( n == 1 ) return;
    if( Miller_Rabin(n) ){
        factor[tot++] = n ;
        return ;
    }
    LL p = n ;
    int c = k ;
    while( p >= n ) p = pollard_rho( p , c-- );

    findfac( p , k );
    findfac( n / p , k );
}

int main(){
    LL n ;
    scanf("%lld",&n);
    if( Miller_Rabin(n) ){
        printf("2\n");
    }else{
        tot = 0 ;
        findfac( n , 107 ) ;
        LL res = 1LL;
        for( int i = 0 ; i < tot ; i++ ){
            int cnt = 0 ;
            while( n > 0 && ( n % factor[i] == 0 ) ){
                cnt ++ ;
                n /= factor[i];
            }
            if( cnt ) res *= ( cnt + 1 );
        }
        printf("%lld\n",res);
    }
    return 0 ;
}

G. Extreme Sort
签到题
Code:

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e3+66;
int a[AX];
int main(){
    int n;
    cin >> n ;
    for( int i = 0 ; i < n ; i ++ ){
        cin >> a[i];
    }
    for( int i = 0 ; i < n ; i++ ){
        for( int j = i + 1 ; j < n ; j++ ){
            if( a[j] < a[i] ){
                cout << "no" << endl;
                return 0 ;
            }
        }
    }
    cout << "yes" << endl;
    return 0 ;  
}

H. Legacy Code
题目链接:https://nanti.jisuanke.com/t/28397
题意:妥妥的英文理解题,理解了秒过。给出2*n行,(n组),所有组第一行构成了程序的所有方法,带有PROGRAM字样的是可执行的,第二行是你执行的名字,(只有带PROGRAM才能执行,进而调用别的方法)
思路:bfs一次即可。
Code:

#include <bits/stdc++.h>
using namespace std;
map<string,int>mp;
const int AX = 1e3+66;
int vis[AX];
std::vector<int> G[AX];
int main(){
    int n ;
    cin >> n ;
    int k ;
    int tot = 1 ;
    queue<int>q;
    for( int i = 0 ; i < n ; i++ ){
        string name ;
        cin >> name >> k;
        if( !mp[name] ) mp[name] = tot ++;
        int id = mp[name];
        if( name.find("::PROGRAM") == name.size() - 9 && name.size() != 8 ){
            q.push(id);
            vis[id] = 1;
        }
        while( k ){
            cin >> name ;
            if( !mp[name] ) mp[name] = tot ++;
            G[mp[name]].push_back(id);
            k --;
        }
    }
    while( !q.empty() ){
        int tmp = q.front();
        q.pop();
        for( int i = 0 ; i < G[tmp].size() ; i++ ){
            if( !vis[G[tmp][i]] ){
                q.push(G[tmp][i]);
                vis[G[tmp][i]] = 1 ;
            }
        }
    }
    int res = 0 ;
    for( int i = 1 ; i < tot ; i++ ){
        if( !vis[i] ){
            res ++ ;
        }
    }
    cout << res << endl;
    return 0 ;
}

I. Milling machines
题目链接:https://nanti.jisuanke.com/t/28398
也是签到题。
Code:

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e4+666;
int a[AX][105];
int b[AX];
int main(){
    int w , s ;
    int x , y ; 
    cin >> w >> s ;
    cin >> x >> y ;
    for( int i = 0 ; i < w ; i++ ){
        for( int j = 0 ; j < x ; j++ ){
            cin >> a[i][j];
        }
    }
    int tmp;
    for( int i = 0 ; i < s ; i++ ){
        for( int j = 0 ; j < x ; j++ ){
            cin >> tmp ;
            b[j] = max( b[j] , tmp );
        }
    }
    for( int i = 0 ; i < w ; i ++ ){
        for( int j = 0 ; j < x ; j++ ){
            cout << ( a[i][j] > ( y - b[j] ) ? (y-b[j]) : a[i][j] ) ;
            if( j != x - 1 ) cout << ' ';
        }
      if( i != w - 1 )  cout << endl;
    } 
    return 0 ;
}

K. Upside down primes
题目链接:https://nanti.jisuanke.com/t/28400
题意:如果输入的数是素数且左右反转一下仍为素数则输出yes,否则no
思路:注意含有3 4 7 的都不行,而且6反过来是9,9反过来是6就行了。
可以用朴素的判断素数,也可以用米勒拉宾素数测试判断更快。
Code:

#include <bits/stdc++.h>
#define LL long long 
using namespace std;
const int AX = 1e2+6;

int main(){
    string s ;
    cin >> s ;
    LL n = 0LL ;
    LL nn = 0LL ;
    int len = s.size();
    if( s.size() == 1 ){
        if( s[0] == '2'  ){
            cout << "yes" << endl;
            return 0 ;
        }
        if( s[0] == '1' ){
            cout <<"no" << endl;
            return 0 ;
        }
    }
    for(int i = 0 ; i < len ; i++ ){
        nn = nn * 10 + ( s[i] - '0' ) ;
    }

    LL lim = sqrt(nn) ;
    for( LL i = 2 ; i <= lim ; i++ ){
        if( nn % i == 0 ){
            cout << "no" << endl;
        return 0 ;
        }
    }
    for(int i = 0 ; i < len ; i++){
        if( s[i] == '3' || s[i] == '4' || s[i] == '7' ){
            cout << "no" << endl;
            return 0 ;
        }
    }
    for( int i = len - 1; i >= 0 ; i-- ){
        if( s[i] == '9' ) n = n * 10 + 6 ;
        else if( s[i] == '6' ) n = n * 10 + 9 ;
        else n = n * 10 + ( s[i] - '0' ) ;
    }
    /*if( Miller_Rabin(nn) && Miller_Rabin(n) ){
        cout << "yes" << endl;
    }else cout << "no" << endl;*/
    lim = sqrt(n) ;
    for( LL i = 2 ; i <= lim ; i++ ){
        if( n % i == 0 ){
            cout << "no" << endl;
            return 0 ;
        }
    }
    cout << "yes" << endl;
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值