题意:每个队伍有个赔率pi,如果你往他身上押x元,它赢了,那么你得到x+(1/pi)x元,否则你一分都得不到。问你最多选几支队伍去押,使得存在一种押的方案,不论你押的那几支队伍谁赢,你都能赚得到钱。
设你往第i支队伍上押ai元,不选的视作零元。
首先可以证明,不论你持有多少钱,不影响最后是否有解;是否有解只跟你往各个队伍上押的比例有关。所以不妨设你持有的钱为常数A。
于是有不等式ai*(1+1/pi)>=A,大胆猜测等号成立时,有最极限的解。于是ai=A/(1+1/pi)。
也就是你往第i支队伍身上押的钱数,占你的总钱数的1/(1+1/pi)。
于是把所有队伍按照1/(1+1/pi)从小到大排序,依次尽量选择即可。
注意!由于精度爆炸,所以要用高精度做分数运算。
import java.util.*; import java.io.*; import java.math.*; public class Main{ public static void main(String[] argc){ BigInteger[] A=new BigInteger[105]; BigInteger[] B=new BigInteger[105]; double[] C=new double[105]; int[] vis=new int[105]; String S; char[] s=new char[105]; Scanner sc = new Scanner (new BufferedInputStream(System.in)); int T=sc.nextInt(); for(int zu=1;zu<=T;++zu){ System.out.printf("Case #%d: ",zu); int n=sc.nextInt(); for(int i=1;i<=n;++i){ long tA=0,tB=0; S=sc.next(); int len=S.length(); s=S.toCharArray(); int colon=0; for(int j=0;j<len;++j){ if(s[j]==':'){ colon=j; break; } } int pos1=colon-1; for(int j=0;j<colon;++j){ if(s[j]=='.'){ pos1=j; } else{ tA=tA*10+s[j]-'0'; } } int pos2=len-1; for(int j=colon+1;j<len;++j){ if(s[j]=='.'){ pos2=j; } else{ tB=tB*10+s[j]-'0'; } } for(int j=1;j<=colon-pos1-len+pos2;++j){ tB*=10l; } for(int j=1;j<=len-pos2-colon+pos1;++j){ tA*=10l; } A[i]=BigInteger.valueOf(tA); B[i]=A[i].add(BigInteger.valueOf(tB)); C[i]=(double)tA/((double)tA+(double)tB); } BigInteger sumA=BigInteger.ZERO,sumB=BigInteger.ONE; for(int i=1;i<=n;++i){ vis[i]=0; } int flag=0; for(int i=1;i<=n;++i){ double minn=2000000000.0; int id=0; for(int j=1;j<=n;++j)if(vis[j]==0){ if(C[j]<minn){ minn=C[j]; id=j; } } vis[id]=1; sumA=sumA.multiply(B[id]).add(sumB.multiply(A[id])); sumB=sumB.multiply(B[id]); if(sumA.compareTo(sumB)>=0){ System.out.println(i-1); flag=1; break; } } if(flag==0){ System.out.println(n); } // for(int i=1;i<=n;++i){ // System.out.print(A[i]); // System.out.printf(" "); // System.out.println(B[i]); // } } sc.close(); } }