[BZOJ2510]-弱题-dp+性质优化矩乘

说在前面

——好吧,这矩阵十分特殊,me没有想到


题目

BZOJ2510传送门

题目大意

现在有 m m 个球,每个球上有一个标号。标号为 i 的球有 ai a i
现在进行 K K 次如下的操作:
随机选取一个球,将其标号+1,如果标号大于 n,则对 n n 取模
现在询问操作之后,每种标号的球期望有多少个

范围:n1000,K2147483647,m108

输入输出格式

输入格式:
第一行三个整数 n,m,K n , m , K ,含义如题
接下来一行 n n 个整数,第 i 个数为 ai a i

输出格式:
输出 n n 个小数,每行一个,第 i 行表示最终标号为 i i 的球的期望个数。保留三位小数


解法

首先很显然的有一个dp式子:dpi=(11m)dpi+1mdpi1
然后构造矩阵尝试优化转移,然后矩阵长这样:
这里写图片描述但是乘一次就是 n3 n 3 ,显然GG

然后我们可以发现,它无论怎么乘,第 i i 行都是第 i1 行循环右移;第 i i 列都是第 i1 列循环下移
所以我们只需要维护矩阵中任意一行的权值,就可以知道整个矩阵
于是乘一次变成了 n2 n 2 ,可过


下面是代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

int N , M , K ;
struct Mat{
    double v[1005] ;
    Mat(){ memset( v , 0 , sizeof( v ) ) ; }
    Mat operator * ( const Mat &A ) const {
        Mat rt ;
        for( int i = 1 ; i <= N ; i ++ ){
            double tmp = 0 ;
            for( int j = 1 ; j <= N ; j ++ )
                tmp += v[j] * A.v[ (i-j+N)%N+1 ] ;
            rt.v[i] = tmp ;
        } return rt ;
    }
} a ;

Mat Mat_s_pow( Mat x , int b ){
    Mat rt ; rt.v[1] = 1 ;
    while( b ){
        if( b&1 ) rt = rt * x ;
        x = x * x , b >>= 1 ;
    } return rt ;
}

void solve(){
    Mat ori , res ;
    ori.v[1] = 1 - 1.0 / M , ori.v[2] = 1.0 / M ;
    res = Mat_s_pow( ori , K ) ;
    a = a * res ;
    for( int i = 1 ; i <= N ; i ++ )
        printf( "%.3f\n" , a.v[i] ) ;
}

int main(){
    scanf( "%d%d%d" , &N , &M , &K ) ;
    for( int i = 1 ; i <= N ; i ++ )
        scanf( "%lf" , &a.v[i] ) ;
    if( N == 1 ) printf( "%.3f\n" , a.v[1] ) , exit( 0 ) ;
    solve() ;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值