版权声明:本博客内容基本为原创,如有问题欢迎联系,转载请注明出处 https://blog.csdn.net/qq_41955236/article/details/84452495
题目链接: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;
}