Hdu 5245 Joyful【滚动数组+概率Dp】

来源:互联网 发布:富通贷网络借贷 编辑:程序博客网 时间:2024/06/04 19:40

Joyful

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1413    Accepted Submission(s): 622


Problem Description
Sakura has a very magical tool to paint walls. One day, kAc asked Sakura to paint a wall that looks like an M×N matrix. The wall has M×N squares in all. In the whole problem we denotes (x,y) to be the square at the x-th row, y-th column. Once Sakura has determined two squares (x1,y1) and (x2,y2), she can use the magical tool to paint all the squares in the sub-matrix which has the given two squares as corners.

However, Sakura is a very naughty girl, so she just randomly uses the tool for K times. More specifically, each time for Sakura to use that tool, she just randomly picks two squares from all the M×N squares, with equal probability. Now, kAc wants to know the expected number of squares that will be painted eventually.
 

Input
The first line contains an integer T(T100), denoting the number of test cases.

For each test case, there is only one line, with three integers M,N and K.
It is guaranteed that 1M,N5001K20.
 

Output
For each test case, output ''Case #t:'' to represent the t-th case, and then output the expected number of squares that will be painted. Round to integers.
 

Sample Input
23 3 14 4 2
 

Sample Output
Case #1: 4Case #2: 8
Hint
The precise answer in the first test case is about 3.56790123.

题目大意:


给你一个N*M的矩阵,进行K次随机操作,每个点被选中的概率都是等同的,每次操作随机选两个点,作为一个矩阵的对角,然后将这个矩阵涂上颜色,问K次操作之后,期望被涂上色的点的个数。点可以被重复涂抹。


思路:


我们没法考虑最终的形状,要不然时间复杂度非常大,所以我们不妨考虑一个点在K次操作之后是否会贡献其本身的价值(即这个点在k次操作之后是否被涂抹了)。


那么设定Dp【i】【x】【y】【2】:

①Dp【i】【x】【y】【0】表示操作了i次之后,(x,y)这个点没有被涂的概率。

②Dp【i】【x】【y】【1】表示操作了i次之后,(x,y)这个点被涂了的概率。


那么状态转移方程并不难写出,考虑到double类型的数据,O(n*m*k)的空间复杂度有些大(实际最开始第一发就交的这个,然后MLE了之后才改的)。我们滚动一下数组再写出状态转移方程有:

这里P【i】【j】表示涂抹一次,(i,j)这个点被涂抹到的概率。


其计算方式也很简单,简单容斥几个公式就行了。这里具体参考一下Ac代码吧。



那么ans=ΣDp【n】【x】【y】【1】;


Ac代码(800+ms过的):


#include<stdio.h>#include<string.h>#include<math.h>using namespace std;#define ll long long intdouble p[501][501];double dp[2][501][501][3];ll Cal(ll a,ll b){    return a*a*b*b;}int main(){    int kase=0;    int t;    scanf("%d",&t);    while(t--)    {        ll n,m,k;        memset(dp,0,sizeof(dp));        scanf("%lld%lld%lld",&n,&m,&k);        for(ll i=1;i<=n;i++)        {            for(ll j=1;j<=m;j++)            {                p[i][j]+=Cal(i-1,m);                p[i][j]+=Cal(n-i,m);                p[i][j]+=Cal(n,j-1);                p[i][j]+=Cal(n,m-j);                p[i][j]-=Cal(i-1,j-1);                p[i][j]-=Cal(i-1,m-j);                p[i][j]-=Cal(n-i,j-1);                p[i][j]-=Cal(n-i,m-j);                double fenmu=n*m*n*m;                p[i][j]/=fenmu;                p[i][j]=1-p[i][j];            }        }        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                dp[0][i][j][0]=1.0;            }        }        for(int z=1;z<=k;z++)        {            for(int i=1;i<=n;i++)            {                for(int j=1;j<=m;j++)                {                    dp[1][i][j][0]+=dp[0][i][j][0]*(1.0-p[i][j]);                    dp[1][i][j][1]+=dp[0][i][j][0]*(p[i][j]);                    dp[1][i][j][1]+=dp[0][i][j][1]*(p[i][j]);                    dp[1][i][j][1]+=dp[0][i][j][1]*(1.0-p[i][j]);                    dp[0][i][j][0]=dp[1][i][j][0];                    dp[0][i][j][1]=dp[1][i][j][1];                    dp[1][i][j][0]=0;                    dp[1][i][j][1]=0;                }            }        }        double output=0;        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                output+=dp[0][i][j][1];            }        }        printf("Case #%d: ",++kase);        printf("%.0f\n",output);    }}











原创粉丝点击