zoj 2570 Arena DP+搜索退化贪心

题意

  N个骑士,分别有个名字和战斗值。现在一个擂台上PK,第一个人上,之后的人一个一个上。若出现替换,则次数加1.

  然后M次询问,每次一个K,问替换次数为K的序列,方案总数,以及字典序(骑士名)最小的方案输出。

解题思路

  DP优化总方案数  

    假定 p_1 < p_2 < ... < p_n

    状态dp[i][k],表示前i个骑士已经分配完策略,这个时候放 j = [ i+1, n ] 中任一个。

    当 p_j 放到 i+1 位置时, [ i+2, p-1 ] 中任意一个其实都不能替换掉 p_j , 则其在 [ i+2, n ] 这些位置可以随意放。

    则我们得出转移方程

        dp( j, k+1 ) += dp( i, k )*C( p-(i+1), n-(i+1) )*( p-(i+1) )!  

  贪心使搜索退化成O(N)不回溯

    我们可以得出一个结论,对于一个序列  p_1, p_2, p_3, ..., p_n 最大替换次数为 M

    若要求替换次数  0 <= x <= M , 总是存在的

    那么我们 按照字典序枚举满足要求的 p_i, 则p_i必定满足要求,而不需要试验其它 P_x

    所以我们可以 通过贪心 使搜索不回溯,退化成 O(N)。

 

赶脚时间复杂度也才O(N^3) 足够AC了。 可惜总方案数达到 99!, 需要FFT来优化大数乘法。

换成JAVA BigInteger 来写,却有TLE。实在无奈了。 不过跟叉姐学到了一个好的分析方式。

C/C++  WA 未处理大数

View Code
#include<cstdio>

#include<cstring>

#include<algorithm>

#include<string>

using namespace std;



typedef unsigned long long LL;



const int N = 110;

struct node{

    string name;

    int c;    

}p[N];

int mp[1010], idx;



int cmp_power( node x, node y ){

    return x.c < y.c;    

}

int cmp_name( node x, node y ){

    return x.name < y.name;    

} 

LL dp[N][N], fact[N], C[N][N];

int n, men[N];

string res[N];

bool vis[N], flag;



void init(){

    fact[0] = 1;

    for(int i = 1; i < N; i++) fact[i]=fact[i-1]*i;

    for(int i = 0; i < N; i++) C[i][0] = C[i][i] = 1;

    for(int i = 2; i < N; i++)

        for(int j = 1; j < i; j++)

            C[i][j] = C[i][j-1] + C[i-1][j-1];

}



void dfs( int m, int cur, int cnt, int num ){

    if( (cur>cnt) || flag ) return;

    if( cur == cnt && num == n ){ 

    //    for(int i = 0; i < num; i++) printf("%d ", men[i]); puts("");

        flag = true; return;}

    for(int i = 0; i < n; i++){

        if( flag ) return;

        if( !vis[i] ){

            int t_max = max( p[i].c, m );

            int t_cur = cur + (p[i].c>m);

            if( (t_cur <= cnt) &&  (n-mp[t_max] >= (cnt-t_cur)) ){

                if( (cnt==t_cur) && (n-mp[t_max]!=0) ) continue;

            //    printf("n-mp[t_max] = %d, cnt-t_cur = %d\n", n-mp[t_max], cnt-t_cur );

                men[num] = i; //printf("i = %d, t_cur = %d\n", i, t_cur );

                vis[i] = 1; 

                dfs( t_max, t_cur, cnt, num+1 );

                break;    

            }

        }    

    }

}

int main(){

    init();

    int m, c, T = 0;

    char str[30];

    while( scanf("%d",&n) != EOF){

        if( T++ > 0 ) puts("");

        memset( dp, 0, sizeof(dp));

        dp[0][0] = 1; 

        for(int i = 0; i < n; i++){

            for(int k = (i==0)?0:1; k <= i; k++){

                if( dp[i][k] <= 0 ) continue;

                for(int j = i+1; j <= n; j++){ 

                    dp[j][k+1] += dp[i][k]*C[n-(i+1)][j-(i+1)]*fact[j-(i+1)];    

                }

            }

        }

    

        for(int i = 0; i < n; i++){

            scanf("%s %d", str, &c );

            p[i].name = str; p[i].c = c;     

        }

        sort( p, p+n, cmp_power );

        for(int i = 0; i < n; i++) mp[ p[i].c ] = i+1;

        sort( p, p+n, cmp_name );

        

        int m, k;

        scanf("%d", &m);

        for(int j = 0; j < m; j++){

            scanf("%d", &k);

            if( k >= n ) printf("-_-\n");

            else{

                memset(vis, 0, sizeof(vis));

                flag = false;

                dfs( -1, -1, k, 0 );

                printf("%I64u\n", dp[n][k+1] );

                for(int i = 0; i < n; i++)

                    printf( i==0?"%s":" %s", p[ men[i] ].name.c_str() );

                puts("");

            }

        }

    }

    return 0;    

}

Java  TLE

View Code
import java.io.*;

import java.text.Bidi;

import java.util.*;

import java.math.*;

class Node{

    public String name;

    public int c;  

}



public class zoj2570 {

    

    static int N = 110;

    static int n, flag;

    static int[] vis = new int[N], men = new int[N], mp = new int[1024];

    static BigInteger[][] C = new BigInteger[N][N];

    static BigInteger[][] dp = new BigInteger[N][N];

    static BigInteger F[] = new BigInteger[N];

    static Node[] p;

    static int max(int a,int b){

        return a > b ? a : b;

    }

    public static void init(){

        F[0] = BigInteger.ONE;

        for(int i = 1; i < N; i++) F[i] = F[i-1].multiply(BigInteger.valueOf(i));

        for(int i = 0; i < N; i++ ) C[i][0] = C[i][i] = BigInteger.ONE;

        for(int i = 2; i < N; i++)

            for(int j = 1; j < i; j++ )

                C[i][j] = C[i-1][j].add( C[i-1][j-1]);

    }

    public static void dfs(int m, int cur, int cnt, int num ){

        if( flag == 1 ) return;

        if( cur == cnt && num == n ){

            flag = 1; return;

        }

        for(int i = 0; i < n; i++ ){

            if( flag == 1 ) return;

            if( vis[i] == 0 ){

                int t_cur = cur + (p[i].c > m ? 1 : 0 );

                int t_max = max( p[i].c, m );

                if( (t_cur<=num) && (n-mp[t_max]>=(cnt-t_cur)) ){

                    if( (cnt==t_cur) && (n-mp[t_max]!=0)) continue;

                    men[num] = i; vis[i] = 1;

                    dfs( t_max, t_cur, cnt, num+1 );

                    break;

                }

            }

        }

    }

    public static void main(String[] args){

        Scanner cin = new Scanner(System.in);

        int T = 0;

        init();

        while( cin.hasNext() ){

            n = cin.nextInt(); p = new Node[n];

            if( n == 0 ) break;

            if( (T++) > 0 ) System.out.println("");

            // input power and name

            for(int i = 0; i < n; i++ ){

                p[i] = new Node();

                p[i].name = cin.next();

                p[i].c = cin.nextInt();

            }

            Collections.sort(Arrays.asList(p),new Comparator<Node>(){

                public int compare( Node a, Node b ){

                    return a.c - b.c;

                }

            });

            //test

            //for(int i = 0; i < n; i++ ){

            //    if(i > 0) System.out.print(" ");

            //    System.out.print(p[i].c);

            //}System.out.println("");

            for(int i = 0; i < n; i++ ){

                mp[ p[i].c ] = i+1;

            }

            Collections.sort(Arrays.asList(p),new Comparator<Node>(){

                public int compare( Node a, Node b ){

                    return a.name.compareTo(b.name);

                }

            });

            //test

            //for(int i = 0; i < n; i++ ){

            //    if(i > 0) System.out.print(" ");

            //    System.out.print(p[i].c);

            //}System.out.println("");

            

            

            for(int i = 0; i <= n; i++)

                for(int j = 0; j <= n; j++ )

                    dp[i][j] = BigInteger.ZERO;

            dp[0][0] = BigInteger.ONE;

            for(int i = 0; i < n; i++ ){

                for(int k = (i==0)?0:1; k <= i; k++ ){

                    if( dp[i][k].compareTo(BigInteger.ZERO) <= 0 )

                        continue;

                    for(int j = i+1; j <= n; j++ ){

                        BigInteger tmp = C[n-(i+1)][j-(i+1)].multiply(F[j-(i+1)]);

                        dp[j][k+1] = dp[j][k+1].add( dp[i][k].multiply(tmp));

                    }

                }

            }

            int m = cin.nextInt(), x;

            for(int y = 0; y < m; y++){

                x = cin.nextInt();

                if( x >= n ) System.out.println("-_-");

                else{

                    for(int i = 0; i < n; i++ ) vis[i] = 0;

                    flag = 0;

                    dfs( -1,-1,x,0 );

                    System.out.println(dp[n][x+1]);

                    for(int i = 0; i < n; i++){

                        if( i > 0 ) System.out.print(" ");

                        System.out.print( p[men[i]].name );

                    }

                    System.out.println("");

                }

            }

        }

    }

}

 

你可能感兴趣的:(ZOJ)