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(""); } } } } }