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 可过。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1010
using namespace std;
int n,m,k;
int a[N];

struct Matrix
{
    double map[N];
};
Matrix ori;
Matrix bas;
Matrix bask;
Matrix ans;
Matrix c;
// f[i][j]表示第i次拿出标号为j的球的期望
// f[i][j]=f[i-1][j]+1/m*f[i-1][j-1]-1/m*f[i-1][j];
Matrix mul(Matrix a,Matrix b)
{
    for(int i=1;i<=n;i++)
    {
        c.map[i]=0;
        for(int j=1;j<=n;j++)
        {
            c.map[i]+=a.map[j]*b.map[(i-j+n+1)%n==0?n:(i-j+n+1)%n];
        }
    }
    return c;
}
Matrix quick_my(Matrix a,int y)
{
    Matrix ret;
    memset(ret.map,0,sizeof(ret.map));
    ret.map[1]=1;
    while(y)
    {
        if(y&1)
        {
            ret=mul(ret,a);
        }
        a=mul(a,a);
        y>>=1;
    }
    return ret;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)ori.map[i]=(double)a[i];
    bas.map[1]=(double)(m-1)/(double)m;
    bas.map[2]=1.0/(double)m;
    bask=quick_my(bas,k);
    ans=mul(ori,bask);
    for(int i=1;i<=n;i++)printf("%.3lf\n",ans.map[i]);
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-28 05:51:02

BZOJ 4204 取球游戏 循环矩阵优化期望递推的相关文章

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时同理) 这个状态显然是开不下的,但是可以考虑矩阵乘法优化: 得到一个形似这样的矩

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

多校第九场:贪心+矩阵快速幂中间优化+线性递推&amp;线段树递推

HDU 4968 Improving the GPA 思路:贪心的搞吧!比赛的时候想了好久,然后才发现了点规律,然后乱搞1A. 因为贪心嘛!大的情况就是刚开始每个人的分数都是最大的最小值,即绩点4.0的最低分数85,然后最后一个数设为剩余的分数,然后如果小于60就从第一个分数补到这个分数来,然后最后一个分数还小于60,那就用第二个补--依次往下搞,那时我也不知道这样就搞出答案了,我还没证明这个对不对呢,哈哈. 小的情况:小的情况就是先假设每个人都是绩点最小的最大分数,即绩点2.0的最大分数69,

HDU 5863 cjj&#39;s string game ( 16年多校10 G 题、矩阵快速幂优化线性递推DP )

题目链接 题意 : 有种不同的字符,每种字符有无限个,要求用这k种字符构造两个长度为n的字符串a和b,使得a串和b串的最长公共部分长度恰为m,问方案数 分析 : 直觉是DP 不过当时看到 n 很大.但是 m 很小的时候 发现此题DP并不合适.于是想可能是某种组合数学的问题可以直接公式算 看到题解的我.恍然大悟.对于这种数据.可以考虑一下矩阵快速幂优化的DP 首先要想到线性递推的 DP 式子 最直观的想法就是 dp[i][j] = 到第 i 个位置为止.前面最长匹配长度为 j 的方案数 但是如果仔

再谈循环&amp;迭代&amp;回溯&amp;递归&amp;递推这些基本概念

循环:不断重复进行某一运算.操作. 迭代:不断对前一旧值运算得到新值直到达到精度.一般用于得到近似目标值,反复循环同一运算式(函数),并且总是把前一 次运算结果反代会运算式进行下一次运算 递推:从初值出发反复进行某一运算得到所需结果.-----从已知到未知,从小到达(比如每年长高9cm,20年180,30后270) 回溯:递归时经历的一个过程. 递归:从所需结果出发不断回溯前一运算直到回到初值再递推得到所需结果----从未知到已知,从大到小,再从小到大(你想进bat,那么编程就的牛逼,就得卸载玩

蓝桥杯 取球游戏

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