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.
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
(
T≤100
), 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 1≤M,N≤500 , 1≤K≤20 .
For each test case, there is only one line, with three integers M,N and K .
It is guaranteed that 1≤M,N≤500 , 1≤K≤20 .
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
2 3 3 1 4 4 2
Sample Output
Case #1: 4 Case #2: 8HintThe 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 int
double 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);
}
}