bzoj-4204 取球游戏

题意:

给出1到n的标号和m个球,每次随机取一个球,将其标号+1之后放回;

如果取出的标号是n就置为1,求执行k次操作之后每种球的期望个数;

n<=1000,m<=10000000,k<=max int;

题解:

设f[t][i]为第t次操作时,标号为i的球的期望个数;

那么很容易列出转移方程:

f[t][i]=f[t-1][i]+1/m*f[t-1][i-1]-1/m*f[t-1][i];

(边界i==1时同理)

这个状态显然是开不下的,但是可以考虑矩阵乘法优化;

得到一个形似这样的矩阵:

然后写一发交上去T了;

恩毕竟n=1000卡得过去才奇怪了;

所以还要优化,递推式已经挺好了,O(n^3logk)的复杂度还是要在n上下手;

再观察矩阵发现,这是一个循环矩阵,而根据百度百科定理可知,循环矩阵的乘积也是循环矩阵;

而保存一个n*n的循环矩阵只需要记录第一行就可以了,乘法也就可以优化到O(n^2);

那么此题就可以O(n^2logk)做出来了;

精度有毒!听说卡精度我就上了long double ,结果挂了;

然后换double过= =;

bzoj 2510土豪们的双倍经验;

代码:

#include<stdio.h>
#include<iomanip>
#include<string.h>
#include<iostream>
#include<algorithm>
#define N 1001
using namespace std;
typedef double ld;
struct matrix
{
	ld a[N];
}now,T,In,ret_mul,ret_pow;
int n;
void mul(matrix &x,matrix &y,matrix &p)
{
	memset(&ret_mul,0,sizeof(matrix));
	for(int i=1;i<=n;i++)
	{
		ret_mul.a[i]=0;
		for(int j=1;j<=n;j++)
			ret_mul.a[i]+=x.a[j]*y.a[(i-j+n)%n+1];
	}
	p=ret_mul;
}
void pow(matrix &x,int y,matrix &p)
{
	ret_pow=In;
	while(y)
	{
		if(y&1)
			mul(ret_pow,x,ret_pow);
		mul(x,x,x);
		y>>=1;
	}
	p=ret_pow;
}
int main()
{
	int m,i,j,k;
	scanf("%d%d%d",&n,&m,&k);
	for(i=1;i<=n;i++)
		cin>>now.a[i];
	In.a[1]=1;
	T.a[1]=1-1.0/m,T.a[2]=1.0/m;
	pow(T,k,T);
	mul(now,T,now);
	cout<<fixed<<setprecision(3);
	for(i=1;i<=n;i++)
		cout<<now.a[i]<<endl;
	return 0;
}
时间: 2025-01-02 05:40:24

bzoj-4204 取球游戏的相关文章

BZOJ 4204 取球游戏 循环矩阵优化期望递推

题意:链接 方法:循环矩阵优化期望递推. 解析: 这题递推没啥,主要是循环矩阵优化 我们发现,如果直接上矩阵优化的话是n^3log,所以铁定是过不了了的,然后再观察一下这道题我们要求幂的矩阵,发现他是这种形式 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 每一行都是上一行向右窜了一位 所以我们可以用一个一维数组代表这个循环矩阵 并且循环矩阵求和,乘积还是循环矩阵 所以我们就可以用循环矩阵来优化掉一个n 复杂度即变为了n^2log 可过. 代码

BZOJ 1413 取石子游戏(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1413 题意:n堆石子排成一排.每次只能在两侧的两堆中选择一堆拿.至少拿一个.谁不能操作谁输. 思路:参考这里. int f1[N][N],f2[N][N],n,a[N]; void deal() { RD(n); int i,j,k; FOR1(i,n) RD(a[i]),f1[i][i]=f2[i][i]=a[i]; int p,q,x; for(k=2;k<=n;k++) for(

BZOJ 1978 取数游戏(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1978 题意:给出一个数列a,在其中找出下标依次增大的数,使得任意相邻的两个数的最大公约数大于等于m.找出最多的数字. 思路:f[i]表示前面的数字中最大公约数为i可以找出的最多的数字个数.那么对于当前数字x: 接着更新f: int f[N],a[N]; int n,m; int main() { RD(n,m); int i; FOR1(i,n) RD(a[i]); int j,k;

BZOJ 1874 取石子游戏 (NIM游戏)

题解:简单的NIM游戏,直接计算SG函数,至于找先手策略则按字典序异或掉,去除石子后再异或判断,若可行则直接输出. #include const int N=1005; int SG[N],b[N],hash[N],a[N],sum,tmp,i,j,n,m; void FSG(int s){ SG[0]=0; for(int i=1;i<=s;i++){ for(int j=1;b[j]<=i&&j<=m;j++)hash[SG[i-b[j]]]=i; for(int j

bzoj 1874 取石子游戏 题解 &amp; SG函数初探

[原题] 1874: [BeiJing2009 WinterCamp]取石子游戏 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 334  Solved: 122 [Submit][Status] Description 小H和小Z正在玩一个取石子游戏. 取石子游戏的规则是这样的,每个人每次可以从一堆石子中取出若干个石子,每次取石子的个数有限制,谁不能取石子时就会输掉游戏. 小H先进行操作,他想问你他是否有必胜策略,如果有,第一步如何取石子. In

蓝桥杯 取球游戏

今盒子里有n个小球,A.B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个, 也可以看到盒中还剩下多少个,并且两人都很聪明,不会做出错误的判断. 我们约定: 每个人从盒子中取出的球的数目必须是:1,3,7或者8个. 轮到某一方取球时不能弃权! A先取球,然后双方交替取球,直到取完. 被迫拿到最后一个球的一方为负方(输方) 请编程确定出在双方都不判断失误的情况下,对于特定的初始球数,A是否能赢? 程序运行时,从标准输入获得数据,其格式如下: 先是一个整数n(n<100),表示接下来有n个整数

bzoj 1874 取石子游戏 题解 &amp;amp; SG函数初探

[原题] 1874: [BeiJing2009 WinterCamp]取石子游戏 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 334  Solved: 122 [Submit][Status] Description 小H和小Z正在玩一个取石子游戏. 取石子游戏的规则是这种,每一个人每次能够从一堆石子中取出若干个石子,每次取石子的个数有限制,谁不能取石子时就会输掉游戏. 小H先进行操作,他想问你他是否有必胜策略,假设有,第一步怎样取石子. In

BZOJ 1978: [BeiJing2010]取数游戏 game( dp )

dp(x)表示前x个的最大值,  Max(x)表示含有因数x的dp最大值. 然后对第x个数a[x], 分解质因数然后dp(x) = max{Max(t)} + 1, t是x的因数且t>=L ----------------------------------------------------------------------------------------- #include<cstdio> #include<cmath> #include<cstring>

BZOJ 1874: [BeiJing2009 WinterCamp]取石子游戏 [Nim游戏 SG函数]

小H和小Z正在玩一个取石子游戏. 取石子游戏的规则是这样的,每个人每次可以从一堆石子中取出若干个石子,每次取石子的个数有限制,谁不能取石子时就会输掉游戏. 小H先进行操作,他想问你他是否有必胜策略,如果有,第一步如何取石子. N≤10 Ai≤1000 裸SG函数啊 然而我连SG函数都不会求了,WA了一会儿之后照别人代码改发现vis公用了... #include <iostream> #include <cstdio> #include <cstring> #includ