1. 程式人生 > >F - Flipping El-fetiera Gym - 101991F 概率 思維

F - Flipping El-fetiera Gym - 101991F 概率 思維

題目連結:http://codeforces.com/gym/101991/problem/F

題意:

        給你n*n的格子,每個格子是0或者1,現在要你取k個子矩陣,每次將這個矩陣中的0變為1,1變為0,那麼問k次操作之後你這n*n個數和的期望是多少。

 

做法:

       先看這個面為1還是0,算出這個格子可能會被抽到的可能性,然後再用組合數和i次方表示取這k次的中能把它翻到1的可能性,加到答案中。具體看程式碼吧。。不知道怎麼形容。


 

#include<bits/stdc++.h>
using namespace std;
typedef long double ld;
ld C[305][305];
int n,mp[305][305];
ld quick(ld a,int m){
    ld ans=1;
    while(m){
        if(m&1) ans=a*ans;
        a=a*a;
        m/=2;
    }
    return ans;
}
ld Calsum(int x,int y){
    return (ld)x*(n-x+1)*y*(n-y+1);
}
ld Calbo(int n){
    return (ld)(n*(1+n)/2);
}
void init(){
    for(int i=0;i<=300;i++){
        C[i][0]=1,C[i][1]=i;
    }
    for(int i=2;i<=300;i++){
        for(int j=1;j<=i;j++){
            C[i][j]=C[i-1][j]+C[i-1][j-1];
        }
    }
}
int main(){
    freopen("fetiera.in","r",stdin);
    init();
    int t,k;
    cin>>t;
    while(t--){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&mp[i][j]);
        ld ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                ld tops=Calsum(i,j);
                ld a = tops/(ld)(Calbo(n)*Calbo(n)),add=0;
                if(mp[i][j]==0){
                    for(int i=1;i<=k;i+=2){
                        add+=C[k][i]*quick(a,i)*quick(1-a,k-i);
                    }
                    ans+=add;
                }
                else {
                   for(int i=0;i<=k;i+=2){
                        //cout<<quick(a,k-i)<<endl;
                        add+=C[k][i]*quick(a,i)*quick(1-a,k-i);
                    }
                    ans+=add;
                }
            }
        }
        printf("%.5Lf\n",ans);
    }
    return 0;
}