Gym10081 A - Arcade Game -康托展开、全排列、组合数变成递推的思想

最近做到好多概率,组合数,全排列的题目,本咸鱼不会啊,我概率论都挂科了。。。

这个题学到了一个康托展开,有点用,瞎写一下。。。

康托展开:

适用对象:没有重复元素的全排列。

把一个整数X展开成如下形式:

X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0![1]

其中a[i]为当前未出现的元素中是排在第几个(从0开始),并且0<=a[i]<i(1<=i<=n)

用来求全排列中这个串排第几,康托展开的逆运算就是找排名第n个的是什么。。。

传送门,懒得写,都差不多 1.(??ω??)   2.( ? ?ω?? )?   3.?(?????)?   4.?(?>?<?)?

直接上题目:

A - Arcade Gam

Arcade mall is a new modern mall. It has a new hammer game called "Arcade Game". In this game you‘re presented with a number n which is hanged on a wall on top of a long vertical tube, at the bottom of the tube there is a button that you should hit with your hammer.

When you hit the button with all your force (as you always do), a ball is pushed all over the tube and hit the number n. The number n flies in the air and it‘s digits fall back in any random permutation with uniform probability.

If the new number formed is less than or equal to the previous number, the game ends and you lose what ever the new number is. Otherwise (if the number is greater than the previous number), you are still in the game and you should hit the button again.

You win if the new number formed is greater than the previous number and it is equal to the greatest possible permutation number.

Can you compute the probability of winning?

Input

The first line of the input contains the number of test cases T. Following that there are T lines represents T test cases. In each line, there is a single integer (1?≤?n?≤?109) the target number. The digits of n are all unique, which means that any 2 digits of n are different.

Output

For each test case, print one line containing the answer. Print the answer rounded to exactly 9 decimal digits.

Example

Input

3952925592

Output

0.0000000000.1666666670.194444444

Note

In the first test case, the answer is 0 because 952 is greater than all 2,5 and 9 permutations so you can‘t win, whatever you do.

In the second test case, the answer is 0.166666667 because you may win by getting number 952 with probability 1/6.

In the third test case the answer is 0.194444444 because you may win by getting number 952 in round1 with probability 1/6 or you can win by getting number 925 in round 1 and then 952 in round 2 with probability 1/6 * 1/6.

这个题就是找出来之后求概率,这里求概率是把符合条件的都加进去,假设10个数,每个数被跳到的概率都是1/10,为P。

假设你要求的是排名第5,那么排名第5的跳到排名第1的有很多种跳法。可以直接跳到第一大,也可以跳2步,也可以跳3步,也可以跳4步。因为最后都是要跳到最大的,所以只求中间的步数的概率就可以,所以就是排列组合的问题,就是P*C(1,1)+P^2*C(1,3)+P^3*C(2,3)+P^4*C(3,3)。但是如果按组合数写的话,会超时,这里把组合数优化一下,写成递推就可以了,极限操作最大就是10^9,而不是(10^9+1)*10^9/2次操作。就是从n^2d的操作变成n的操作,但是递推怎么想呢。

抽抽一下,发现,跳1步为0,从第2大跳到第1大赢的概率就是Q1=P,从第3大开始跳获胜的概率就是Q2=P+P*Q1=Q1*(1+P),从第4大开始跳获胜的概率就是Q3=P+P*Q2+P*Q1=Q2*(1+P),从第5大开始跳获胜的概率就是Q4=P+P*Q3+P*Q2+P*Q1=Q3*(1+P)。写的乱七八糟,不知道能不能看懂。。。

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 const int N=1e7+10;
 8 typedef long long ll;
 9 ll fac[N];
10 bool cmp(char a,char b){
11     return a>b;
12 }
13 void jiecheng(){     //阶乘
14     fac[0]=1;
15     for(int i=1;i<10;i++){
16         fac[i]=fac[i-1]*i;
17     }
18 }
19 int kangtuo(char s[],int n){    //康托展开
20     int cnt,sum;
21     sum=0;
22     jiecheng();
23     for (int i=0;i<n;++i){
24         cnt=0;
25         for(int j=i+1;j<n;++j)
26             if(s[j]<s[i])++cnt;
27         sum+=cnt*fac[n-i-1];
28     }
29     return sum;
30 }
31 char s[N];
32 double ans[N];
33 int main(){
34     int t;
35     scanf("%d",&t);
36     while(t--){
37         memset(s,0,sizeof(s));
38         scanf("%s",s);
39         int len=strlen(s);
40         int num1=kangtuo(s,len)+1;   //该数的排名,第几大
41         //cout<<num1<<endl;
42         sort(s,s+len,cmp);
43         int num2=kangtuo(s,len)+1;   //最大的数的排名就是全排列一共多少个数
44         //cout<<num2<<endl;
45         double gailv=1.0/num2;
46         //cout<<gailv<<endl;
47         //cout<<num2-num1<<endl;
48         ans[0]=0;ans[1]=gailv;
49         for(int i=2;i<=num2-num1;i++){  //递推
50             ans[i]=ans[i-1]*(1+gailv);
51         }
52         printf("%.9f\n",ans[num2-num1]);
53     }
54     return 0;
55 }

太智障了,好蠢啊。。。

原文地址:https://www.cnblogs.com/ZERO-/p/8328432.html

时间: 2024-10-09 19:58:54

Gym10081 A - Arcade Game -康托展开、全排列、组合数变成递推的思想的相关文章

Uva 10943 - How do you add ?( 组合数公式 + 递推 )

Uva 10943 - How do you add ?( 组合数公式 + 递推 ) 题意:给定一个数N,分解韡k个数,问有多少种组合.数可以重复 (N<=100) 分析:通过组合数学将题目抽象为 N个相同的小球,放入k个不同的盒子中,且允许盒子为空然后就可以用隔板法------> ANS = C(N+M-1,M-1)隔板法--> BD然后再根据组合数的性质可以进行递推(这题数据范围比较小)----> C(A,B) = C(A-1,B) + C(A-1,B-1);预处理一遍之后即可

康托展开-全排列的编码与解码

一.康托展开:全排列到一个自然数的双射 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! ai为整数,并且0<=ai<i(1<=i<=n) 适用范围:没有重复元素的全排列 二.全排列的编码: {1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个? 如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321.想知道321是{1,2,3}中

康托展开-全排列应用

我排第几个 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 现在有"abcdefghijkl"12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的? 输入 第一行有一个整数n(0<n<=10000);随后有n行,每行是一个排列: 输出 输出一个整数m,占一行,m表示排列是第几位: 样例输入 3 abcdefghijkl hgebkflacdji gfkedhjblcia 样例输出 1 30271524

SDUT 2241-计算组合数C(n,m)(递推)

题目链接:点击打开链接 线性O(n) 计算组合数,递推法. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cctype> #include <vector> #include <cstdio> #include <cmath> #in

LightOJ1060 nth Permutation(不重复全排列+逆康托展开)

一年多前遇到差不多的题目http://acm.fafu.edu.cn/problem.php?id=1427. 一开始我还用搜索..后来那时意外找到一个不重复全排列的计算公式:M!/(N1!*N2!*...*Nn!), 然后就靠自己YY出解法,搞了好几天,最后向学长要了数据,然后迷迷糊糊调了,终于AC了. 后来才知道当时想的解法类似于逆康托展开,只是逆康托展开是对于没有重复元素全排列而言,不过有没有重复元素都一个样. 而现在做这题很顺,因为思路很清晰了,另外这做法和数论DP的统计部分有相似之处.

康托展开:对全排列的HASH和还原,判断搜索中的某个排列是否出现过

题目:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=2297 前置技能:(千万注意是从0开始数的 康托展开表示的是当前排列在n个不同元素的全排列中的名次.比如213在这3个数所有排列中排第3. 那么,对于n个数的排列,康托展开为: 其中表示第i个元素在未出现的元素中排列第几.举个简单的例子: 对于排列4213来说,4在4213中排第3,注意从0开始,2在213中排第1,1在13中排第0,3在

全排列的编码与解码——康托展开

.康托展开:全排列到一个自然数的双射 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! ai为整数,并且0<=ai<i(1<=i<=n) 适用范围:没有重复元素的全排列 二.全排列的编码: {1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个? 如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321.想知道321是{1,2,3}中第

全排列和康托展开

一.康托展开:全排列到一个自然数的双射 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! ai为整数,并且0<=ai<i(1<=i<=n):其中X最常见的可以设为:0 <=X<=n!-1,第一个排列即123...n;该排列的X可设为0: 适用范围:没有重复元素的全排列 二.全排列的编码: {1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个? 如 {1,2

康托展开和逆康托展开

问题:给定的全排列,计算出它是第几个排列? 对于全排列,不清楚的可以参考全排列 方法:康托展开 对于一个长度为 n 的排列 num[1..n], 其序列号 X 为 X = a[1]*(n-1)! + a[2]*(n-2)! +...+ a[i]*(n-i)! +...+ a[n-1]*1! + a[n]*0! 其中a[i]表示在num[i+1..n]中比num[i]小的数的数量 写做伪代码为: Cantor(num[]) X = 0 For i = 1 .. n tp = 0 For j = i