题目链接:HDU5159
【题意】桌子上有a张牌,每张牌从1到a编号,编号为i(1<=i<=a)的牌上面标记着分数i , 每次从这a张牌中随机抽出一张牌,然后放回,执行b次操作,记第j次取出的牌上面分数是 S j , 问b次操作后不同种类分数之和的期望是多少。
【分析】 数学没学好公式不会推,比赛的时候就找到规律了,但是要高精度又带小数,想到用JAVA写,但是好长时间没用JAVA了,导致来不及写出来就结束比赛了;讲下规律,写了个暴力代码发现:
答案就是所有排列中不同的数的和sum/排列总数cnt
cnt很容易得出就是x^b;
打表发现1~x每个数出现的次数都是相同的p,而p=x^b-(x-1)^b;
这样sum就是(1+x)*x/2 * p;
求出了sum和cnt答案就是sum/cnt了
但是sum和cnt超出double范围了,只能用JAVA的BigDecimal,还需要预处理不然超时;
【AC CODE】8065ms
import java.util.*; import java.math.BigDecimal; import java.io.*; import java.text.DecimalFormat; public class Main{ static BufferedReader in = new BufferedReader(new InputStreamReader (System.in)); static BufferedWriter out = new BufferedWriter(new OutputStreamWriter (System.out)); static double[][] ans = new double[100000+10][6]; static BigDecimal[] cnt = new BigDecimal[6]; static DecimalFormat df = new DecimalFormat("0.000"); public static void main(String args[])throws Exception{ BigDecimal one = BigDecimal.valueOf(1); BigDecimal two = BigDecimal.valueOf(2); BigDecimal buf = BigDecimal.valueOf(0); for(int i = 1; i <= 5; i++) { cnt[i] = one; ans[1][i] = 1.0; } cnt[0] = one; BigDecimal oc, p; for(int i = 2; i <= 100000; i++){ BigDecimal I = BigDecimal.valueOf(i); for(int j = 1; j <= 5; j++){ oc = cnt[j]; cnt[j] = cnt[j-1].multiply(I); cnt[j].setScale(10, BigDecimal.ROUND_HALF_UP);//不加容易超时 p = cnt[j].subtract(oc); buf = I.add(one).multiply(I); buf = buf.divide(two,10,BigDecimal.ROUND_HALF_UP); buf = buf.multiply(p); buf = buf.divide(cnt[j],10,BigDecimal.ROUND_HALF_UP); ans[i][j] = buf.doubleValue(); } } /*============ =============*/ int t = Integer.parseInt(in.readLine()); int ct = 1; for (int i = 0; i < t; i++){ StringTokenizer st = new StringTokenizer(in.readLine()); int x = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); System.out.print("Case #"); String num = df.format(ans[x][b]); System.out.println(ct + ": " + num); ct++; } } }
【附上暴力打表的C++代码】
#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <map> //#include <unordered_map> #include <queue> #include <stack> #include <vector> #include <string> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) const int INF = 0x3f3f3f3f, MAXN = 100000+10; int a,b, sum, cnt, num[10]; bool vis[MAXN]; int time[MAXN]; void dfs(int p) { if(p == b) { int tol = 0; rep(i,0,b) { if(!vis[num[i]]) vis[num[i]] = true, tol += num[i], time[num[i]]++; } rep(i,0,b) vis[num[i]] = false; sum += tol; cnt++; return; } repe(i,1,a) { num[p] = i; dfs(p+1); } } int main() { #ifdef SHY freopen("e:\\1.txt", "r", stdin); #endif int t, count = 0; scanf("%d%*c", &t); while(t--) { scanf("%d %d%*c", &a, &b); sum = cnt = 0; int sum2 = 0; clc(time,0); dfs(0); printf("%d %d\n", a,b); repe(i,1,a) { printf("%d) %d\n", i,time[i]); //sum2 += time[i]*i; //printf("%d\n", sum2); } int p = pow(1.0*a,1.0*b)-pow(1.0*(a-1),1.0*b); printf("== %d ==\n", p); printf("Case #%d: %.3lf\n", ++count, (double)sum/((double)cnt)); } return 0; } /* 15 1 1 1 2 1 3 1 4 1 5 2 1 2 2 2 3 2 4 2 5 3 1 3 2 3 3 3 4 3 5 */