【JZOJ B组】【NOIP2013模拟9.29】TheSwaps

Description

Alice得到了一个整数, 她将其视作长度为n的字符串S。为了好玩,她进行了k次如下操作:

1) 随机选取两个不同的位置x和y(即每次操作, {

Input

一行,包含字S和k。

Output

一行,一个实数。当你的输出和标准答案的差距少于10^-6时,被认为是正确的。

Sample Input

输入1:

477 1

输入2:

57268508514909598902647806463326698034850446919720257361969 7

Sample Output

输出1:

10

输出2:

98.3238536775161

Data Constraint

对于70%的数据 |S|<=2500,k<=1000000

对于100%的数据 |S|<=1000000,k<=1000000

思路

k次交换后,ANS=每一位的期望值*每一位被选出的概率。
显然第i位被选出的概率=包含i的子串数/总子串数=i*(n-i+1)/(n*(n+1)/2)。
那如何求k次交换后每一位的期望值?
我们假设最初第i位为ai,p次交换后第i位仍然等于ai的概率是x,那么p+1交换后第i为仍然等于ai的概率是x*(1-(n-1)/q))+(1-x)/q,其中q=n*(n-1)/2。
接下来有一个性质:如果第i位不为ai,那么第i位是a中其他任何数的概率都是一样的(交换的随机性决定的)。
因此如果k次交换后,第i位为ai的概率是x,那么第i位的期望值=ai*x+(sum-ai)/(n-1)*(1-x)。
至此问题就可以解决了。

代码

#include
#include
#include
using namespace std;
int k,a[1000077],n,ss;
double ass=0;
char s[1000077];
int main()
{
    scanf("%s %d",s,&k);
    n=strlen(s);
    for(int i=1; i<=n; i++) a[i]=s[i-1]-48,ss+=a[i];
    double x=1,q=(double)n*(n-1.0)/2.0;
    for(int i=1; i<=k; i++) x=(double)x*(1.0-(n-1.0)/q)+(double)(1.0-x)/q;
    for(int i=1; i<=n; i++)
    {
        double e=(double)i*(n-i+1.0)/(n*(n+1.0)/2.0);
        double p=(double)a[i]*x+(double)(ss-a[i])/(n-1.0)*(1.0-x);
        ass+=e*p;
    }
    printf("%.9lf",ass);
}

你可能感兴趣的:(题解,math)