hdu-4576-Robot 二分&DP

本文介绍了一道来自杭电OJ的DP+概率问题的解题思路与代码实现。该题需要通过预处理相同步数的概率分布,并采用二分合并的方法来减少计算复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=4576

题目有意思

一开始就觉得直接DP会超时 就没敢写

可是后来他们竟然都过了....

这题因为概率和走步的顺序无关  所以先把走相同步数的先统计

相同步数统计出后二分合并,再和其他步数的合并

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXSIZE 200
#define MAX_COMMAND 100
using namespace std;
int         fund[25];
int         n, m, l, r;
double      bina[MAX_COMMAND+5][25][MAXSIZE+5], ans[MAX_COMMAND+5][MAXSIZE+5];
double      tmp[MAXSIZE+5], last[MAXSIZE];
int         num[MAX_COMMAND+5];
void merge(double *x, double *y)
{
    int     i, j, pos;
    double  xx[MAXSIZE+5], yy[MAXSIZE+5];
    x++; y++;
    for (i = 1; i <= n; i++) { xx[i] = *x; x++; }
    for (i = 1; i <= n; i++) { yy[i] = *y; y++; }
    for (i = 1; i <= n; i++) tmp[i] = 0;
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n; j++)
        {
            pos = (i+j-1)%n;
            if (pos == 0) pos = n;
            tmp[pos] += xx[i]*yy[j];
        }
    }
}
int main()
{
    int     i, j, k, p, q;
    double  output;
    fund[0] = 1;
    for (i = 1; i <= 20; i++) fund[i] = fund[i-1]*2;
    scanf("%d %d %d %d", &n, &m, &l, &r);
    while (n != 0)
    {
        memset(num, 0, sizeof(num));
        for (i = 1; i <= MAX_COMMAND; i++)
            for (j = 1; j <= MAXSIZE; j++) ans[i][j] = 0;
        for (i = 1; i <= MAX_COMMAND; i++)
            for (j = 0; j <= 20; j++)
                for (k = 1; k <= MAXSIZE; k++) bina[i][j][k] = 0;
        for (i = 1; i <= MAXSIZE; i++) last[i] = 0;
        for (i = 1; i <= m; i++)
        {
            scanf("%d", &j);
            num[j]++;
        }
        for (i = 1; i <= MAX_COMMAND; i++)
        {
            if (num[i] == 0) continue;
            if ((((1+i)%n)+n)%n != 0) bina[i][0][(((1+i)%n)+n)%n] = 0.5;
                else bina[i][0][n] = 0.5;
            if ((((1-i)%n)+n)%n != 0) bina[i][0][(((1-i)%n)+n)%n] += 0.5;
                else bina[i][0][n] += 0.5;
            for (j = 1; j <= 20; j++)
            {
                merge(bina[i][j-1], bina[i][j-1]);
                for (k = 1; k <= n; k++) bina[i][j][k] = tmp[k];
            }
            p = num[i];
            q = 19;
            ans[i][1] = 1;
            while (p != 0)
            {
                if (p >= fund[q])
                {
                    merge(ans[i], bina[i][q]);
                    for (k = 1; k <= n; k++) ans[i][k] = tmp[k];
                    p -= fund[q];
                }
                else q--;
            }
        }
        last[1] = 1;
        for (i = 1; i <= MAX_COMMAND; i++)
        {
            if (num[i] == 0) continue;
            merge(last, ans[i]);
            for (j = 1; j <= n; j++) last[j] = tmp[j];
        }
        output = 0;
        for (i = l; i <= r; i++) output+=last[i];
        printf("%.4f\n", output);
        scanf("%d %d %d %d", &n, &m, &l, &r);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值