列表

详情


NC21167. 随机采矿

描述

为了不造成混淆, 请明确时刻和时间的区别(拿出初中或高中物理课本中学到的知识).
Jim有一个晶体矿, 在第0时刻有n个SCV来采集矿物, 晶体矿最多能容纳m个SCV,一个单位时间内一个SCV采集晶体矿的效率为k单位晶体
然而控制中心可以花一个单位时间制造一个SCV,在第t个时刻它决定制造一个SCV的概率是
也就是说如果在t时刻开始制造SCV, 在t+1时刻会被制造完成, 另外, 当矿场已经拥有m个SCV时, 将不再制造SCV.
请问他在T单位时间内得到的期望的晶体矿的数量是多少呢?

输入描述

一行4个整数, n, m, T, k.含义如题目描述所示.

输出描述

一个浮点数, 表示期望获得晶体矿的数量.
本题采用spj,你的答案被视为正确当且仅当与标准答案的绝对或相对误差小于10-6
这句话的意思是若你的答案为A, 正确答案为B, 则当 |A - B| < 10 ^ 6 或 | ( A - B ) / A | < 10 ^ 6 时你的答案正确, 两个条件只需满足其中一个.

示例1

输入:

6 10 1 1

输出:

6

说明:

第0个时刻它有100%的概率新建一个SCV.
此时6个SCV采了6单位晶体.
第1时刻采集矿物完成,共采集6单位晶体.

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 1360ms, 内存消耗: 376K, 提交时间: 2020-01-26 15:55:58

#include <cstdio>
#include <cstring>
const int N=25;
struct Matrix{double a[N][N];};
using namespace std;
inline Matrix Mul(Matrix m1,Matrix m2){
    Matrix ret;
    memset(ret.a,0,sizeof(ret.a));
    for(int i=1;i<N;i++)for(int k=1;k<N;k++){
        if(m1.a[i][k]==0) continue;
        for(int j=1;j<N;j++) ret.a[i][j]+=m1.a[i][k]*m2.a[k][j];
    }return ret;
}inline Matrix ksm(Matrix m,int p){
    Matrix ret;
    memset(ret.a,0,sizeof(ret.a));
    for(int i=1;i<N;i++) ret.a[i][i]=1;
    while(p){if(p&1)ret=Mul(ret,m);m=Mul(m,m),p>>=1;}
    return ret;
}int main(){
    int n,m,t,k,ni;
    scanf("%d%d%d%d",&n,&m,&t,&k);
    Matrix m1;
    memset(m1.a,0,sizeof(m1.a));
    m1.a[1][1]=1;
    for(int i=1;i<=t;i=ni+1){
        ni=t/(t/i);
        Matrix m2;
        double val=1.0*(t/i)/t;
        for(int j=1;j<=m-n;j++) m2.a[j][j]=1-val,m2.a[j+1][j]=val;
        m2.a[m-n+1][m-n+1]=1;
        for(int j=1;j<=m-n+1;j++) m2.a[m-n+2][j]=n+j-1;
        m2.a[m-n+2][m-n+2]=1;
        m1=Mul(ksm(m2,ni-i+1),m1);
    }printf("%.8lf\n",m1.a[m-n+2][1]*k);
}

C++11(clang++ 3.9) 解法, 执行用时: 970ms, 内存消耗: 608K, 提交时间: 2019-10-04 14:17:46

#include<bits/stdc++.h>
using namespace std;
bool s1;
int n,m,T,k;
double p;
struct ll{
	double A[22][22];
	void Init(){
		memset(A,0,sizeof(A));
		for(int i=n;i<=m;i++){
			if(i==m)A[i][i]=1;
			else {
				A[i][i]=1-p;
				A[i+1][i]=p;
			}
			A[m+1][i]=1.0*i;
		}
		A[m+1][m+1]=1;
	}
	ll operator *(const ll &a){
		ll res;
		memset(res.A,0,sizeof(res.A));
		for(int i=n;i<=m+1;i++)for(int j=n;j<=m+1;j++)for(int k=n;k<=m+1;k++)res.A[i][j]+=A[i][k]*a.A[k][j];
		return res;
	}
}Ans,num;
void fast(int x){
	num.Init();
	while(x){
		if(x&1)Ans=Ans*num;
		num=num*num;
		x>>=1;
	}
}
bool s2;
int main(){
	int sum=0;
	scanf("%d%d%d%d",&n,&m,&T,&k);
	Ans.A[n][m+1]=1;
	for(int r=T;r;){
		int l=(T/(T/r+1))+1;//从l 到 r 概率相等 
		p=(T/r)*1.0/T;
		fast(r-l+1);
		r=l-1;
	}
	printf("%.6lf\n",Ans.A[n][n]*k);
	return 0;
}

上一题