jjzjj

CF908D New Year and Arbitrary Arrangement 题解

Altwilio 2023-03-28 原文

\(0.\) 前言

有一天 \(Au\) 爷讲期望都见到了此题,通过写题解来加深理解。

\(1.\) 题意

将初始为空的序列的末尾给定概率添加 \(a\)\(b\),当至少有 \(k\)\(ab\) 时停止(注意是“对”,中间可以间隔字符),求 \(ab\) 期望对数。

\(2.\) 思路

通过查看标签 通过阅读题面我们容易发现本题是一道期望 DP,但是本题的状态并不很容易想到,设 \(f[i][j]\) 表示前缀中有 \(i\)\(a\)\(j\)\(ab\) 停止后的期望个数,这样发现转移就容易了很多,不会被 \(a\)\(b\) 纠缠不清,设 \(A = pa / (pa + pb)\)\(B = pb / (pa + pb)\),则有:

\[f[i][j] = A × f[i + 1][j] + B × f[i][j + 1] \]

\(i + j ⩾ k\),则再加一个 \(b\) 就会结束,此时的期望 \(ab\) 数是:

\[i + j + pa / pb \]

故终止状态为:

\[f[i][j] = i + j + pa / pb, i + j ⩾ k \]

\(3.\) 解释

(本块主要针对 \(i + j + pa / pb\) 的推导,不感兴趣可以跳过)

我一直疑惑 \(i + j + pa / pb\) 如何得出。

解释一下,在前缀有了 \(i\)\(a\),构成了 \(j\)\(ab\) 的情况下,若 \(i + j ⩾ k\),这个状态的后继情况能是容易看到的:选 \(a\) ,然后继续抉择,或选 \(b\) ,就此停止。多选一个 \(a\),就意味着最后的 \(ab\) 串又多了一个。 那么得出无限和式:

\[{b \over pa+pb}×\sum_{a=0}^{∞}(i+j+a)×({pa \over pa+pb})^{a} \]

接下来的证明部分参考一粒夸克的博客

首先是等差乘等比数列求和公式

\[(1):A=a+(a+p)×p+(a+2×b)×p^2+...+(a+n×b)×p^n \]

\[(2):A×p=a×p+(a+b)×p^2+(a+2×b)×p^3+...+(a+n×b)×p^{n+1} \]

\[(1)-(2):A×(1-p)=a+b×(p+p^2+p^3+...+p^n)-(a+n×b)p^{n+1} \]

\[A×(1-p)=a+b×p×{1-p^n \over 1-p}-(a+n×b)×p^{n+1} \]

\[A={a\over1-p}+b×{p-p^{n+1}\over(1-p)^2}-{(a+n×b)×p^{n+1}\over1-p} \]

将公式代入无限和式

\[{pb \over pa+pb}×(\sum_{a=0}^{∞}(i+j+a)×({pa \over pa+pb})^{a}) \]

\[={pb\over pa+pb}×({i+j\over1-{pa\over pa+pb}}+{{pa \over pa+pb}-({pa \over pa+pb})^{∞+ 1} \over (1-{pa \over pa+pb})^2}-{(i+j+n)×({pa \over pa+pb})^{∞+1} \over1-{pa \over pa+pb}}) \]

\[={pb\over pa+pb}×({i+j \over {pb \over pa+pb}}+{{pa \over pa+pb}-({pa \over pa+pb})^{∞+ 1} \over ({pb \over pa+pb})^2}-{(i+j+n)×({pa \over pa+pb})^{∞+1} \over{pa \over pa+pb}}) \]

\[=i+j+{{pa \over pa+pb}-({pa \over pa+pb})^{∞+ 1} \over {pb \over pa+pb}}-(i+j+n)×({pa \over pa+pb})^{∞+ 1} \]

\[=i+j+{{pa \over pa+pb}\over {pb \over pa+pb}} \]

\[=i+j+{pa \over pb} \]

(这么巨量\(\LaTeX\)我都打了,求赞)

\(4.\) 细节

  1. 由于 \(f[0][0]\) 会转移到自己,递归记忆化会死循环,从 \(f[1][0]\) 开始算,当序列前有一堆 \(b\) 的情况没有意义,可以跳到第一个 \(a\) 发生时开始算。初始状态选取 \(f[1][0]\)
  2. \(a\)\(ab\) 的个数相加已经大于 \(k\) 了,这是就不关心有多少 \(a\) 了,只需要有一个 \(b\) 就可以结束了,这样可以把两维都控制在 \(O(k)\) 的复杂度

\(5.\) 代码

这是一份逆推实现的代码:

#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;

template<class T> inline void read(T &x){
    x = 0; register char c = getchar(); register bool f = 0;
    while(!isdigit(c)) f ^= c == '-', c = getchar();
    while(isdigit(c)) x = x * 10 + c - '0', c = getchar();
    if(f) x = -x;
}

template<class T> inline void print(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x > 9) print(x / 10);
    putchar('0' + x % 10);
}

const int N = 1010;
const int mod = 1e9 + 7;
int n, pa, pb, A, B, C;
int f[N][N];

inline int qpow(int a, int b){
    int res = 1;
    while(b){
        if(b & 1) res = 1ll * res * a % mod;
        a = 1ll * a * a % mod, b >>= 1;
    }
    return res;
}

inline int work(int x){
	return qpow(x, mod - 2);
}

signed main(){
	read(n), read(pa), read(pb);
    A = 1ll * pa * work(pa + pb) % mod;
    B = 1ll * pb * work(pa + pb) % mod;
    C = 1ll * pa * work(pb) % mod;
    for(int i = n; i >= 1; --i)
        for(int j = n; j >= 0; --j){
            if(i + j >= n) f[i][j] = (i + j + C) % mod;
            else f[i][j] = (1ll * A * f[i + 1][j] % mod + 1ll * B * f[i][j + i] % mod) % mod;
        }
    print(f[1][0]), puts("");
    return 0;
}

这是一份记搜实现的代码片段:

inline int dp(int i, int j){
	if(i + j >= k) return (i + j + C) % mod;
	if(~ f[i][j]) return f[i][j];
	return (1ll * A * dp(i + 1, j) + 1ll * B * dp(i, j + i)) % mod;
}

有关CF908D New Year and Arbitrary Arrangement 题解的更多相关文章

  1. 【算法题解】20. 两数之和 - 2

    这是一道简单题题目来自:https://leetcode.cn/problems/two-sum/题目给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。提示:22nums.length104−109−109nums[i]109−109−109target109只会存在一个有效答案进阶:你可以想出一个时间复杂度小于O(n2)O(n^2)O(n2)的算法吗?示例1:输入:nums=[2,7,11,15],targe

  2. javascript - 使用 javascript 获取 Cloudflare 的 HTTP_CF_IPCOUNTRY header ? - 2

    有很多关于如何使用javascript获取httpheader的问题,但由于某些原因,它们没有显示HTTP_CF_IPCOUNTRYheader。如果我尝试使用phpecho$_SERVER["HTTP_CF_IPCOUNTRY"];,它会工作,所以CF工作得很好。是否可以使用javascript获取此header? 最佳答案 @Quentin的回答是正确的,适用于任何试图访问服务器header的javascript客户端。但是,由于这个问题特定于Cloudlfare,并且特定于在HTTP_CF_IPCOUNTRYheader中正常

  3. 蓝桥杯第十四届省赛完整题解 C/C++ B组 - 2

    没有测评,不知道对不对,仅仅过样例而已试题A:日期统计本题总分:5分【问题描述】小蓝现在有一个长度为100的数组,数组中的每个元素的值都在0到9的范围之内。数组中的元素从左至右如下所示:5686916124919823647759503875815861830379270588570991944686338516346707827689565614010094809128502533现在他想要从这个数组中寻找一些满足以下条件的子序列:   1.子序列的长度为8;   2.这个子序列可以按照下标顺序组成一个yyyymmdd格式的日期,并且要求这个日期是2023年中的某一天的日期,例如202309

  4. javascript - CF连接到云 Controller - 2

    我使用以下库连接到云Controllerhttps://github.com/prosociallearnEU/cf-nodejs-clientconstendpoint="https://api.mycompany.com/";constusername="myuser";constpassword="mypass";constCloudController=new(require("cf-client")).CloudController(endpoint);constUsersUAA=new(require("cf-client")).UsersUAA;constApps=new

  5. 2023第十四届蓝桥杯C/C++B组省赛题解 - 2

    2023蓝桥C/C++B组省赛文章目录2023蓝桥C/C++B组省赛试题A:日期统计题目描述枚举参考代码试题B:01串的熵题目描述枚举|模拟参考代码试题C:冶炼金属题意描述取交集参考代码试题D:飞机降落题意描述DFS+剪枝,懒得写试题E:接龙数列题意描述DP参考代码试题F:岛屿个数题意描述dfs|连通块参考代码试题G:子串简写题意描述前缀和参考代码试题H:整数删除题意描述双向链表|最小堆参考代码试题I:景区导游题意描述带权LCA参考代码试题J:砍树题意描述树上差分参考代码试题A:日期统计题目描述【问题描述】小蓝现在有一个长度为100的数组,数组中的每个元素的值都在0到9的范围之内。数组中的元素

  6. linux - 构建 cf-cli : go build runtime: linux/386 must be bootstrapped using make. bash 时出错 - 2

    CloudFoundry的CLI工具位于cloudfoundry/cli是用围棋写的。我正在尝试构建CLI工具但出现此错误:gobuildruntime:linux/386必须使用make.bash引导如何解决这个问题?下面是cli/bin/build-all.sh脚本的内容:#!/bin/bashset-eset-xOUTDIR=$(dirname$0)/../outGOARCH=amd64GOOS=windows$(dirname$0)/build&&cp$OUTDIR/cf$OUTDIR/cf-windows-amd64.exeGOARCH=386GOOS=windows$(di

  7. LeetCode——链表简单题题解 - 2

    83.删除排序链表中的重复元素题目描述给定一个已排序的链表的头head,删除所有重复的元素,使每个元素只出现一次。返回已排序的链表。输入:head=[1,1,2]输出:[1,2]解题思路:用一个指向节点类型的指针保存头结点,用另一个指向节点类型的指针对该链表进行遍历,由于是有序的,当出现不同的值就说明不会再出现跟前面的值相同的节点了,最后循环结束的条件是遍历到最后一个节点的时候,也就是该节点的next指向空的时候,停止循环,返回该保存的头结点,另外,如果传过来的头结点是空,则直接返回空。参考代码:/***Definitionforsingly-linkedlist.*structListNod

  8. NEUQ week 12 题解 - 2

    P1776宝物筛选宝物筛选题目描述终于,破解了千年的难题。小FF找到了王室的宝物室,里面堆满了无数价值连城的宝物。这下小FF可发财了,嘎嘎。但是这里的宝物实在是太多了,小FF的采集车似乎装不下那么多宝物。看来小FF只能含泪舍弃其中的一部分宝物了。小FF对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小FF有一个最大载重为WWW的采集车,洞穴里总共有nnn种宝物,每种宝物的价值为viv_ivi​,重量为wiw_iwi​,每种宝物有mim_imi​件。小FF希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。输入

  9. c# - XmlSerializer 在 .NET 3.5 和 CF.NET 3.5 之间有所不同 - 2

    我有一个在CF.NET和.NET下运行的库,但两者之间的序列化不同。因此,在CF.NET下生成的XML文件在.NET下不可读,这对我来说是个大问题!这里是代码示例:[Serializable,XmlRoot("config")]publicsealedclassRemoteHost:IEquatable{//...}publicclassProgram{publicstaticvoidMain(){RemoteHosthost=newRemoteHost("A");Listhosts=newList();hosts.Add(host);XmlSerializerser=newXmlSe

  10. Windows CF_DIB 到剪贴板中的 CF_BITMAP - 2

    我完全没有使用过Windows编程,但现在我有一个问题想在某个程序中修复。我需要将图像放置到Windows剪贴板,并且我有指向有效DIB(设备独立位图)的原始指针(在我的实验中,dibheader版本为3)。该程序使用具有延迟剪贴板渲染的模型,这意味着首先我们使用SetClipboardData(CF_DIB,NULL)然后在WM_RENDERFORMAT消息上程序将实际数据放入剪贴板使用SetClipboardData(format,dibDataPointer)。当我打开clipbrd.exe(在windowsxp上)并选择DIBView时,我可以毫无问题地看到图像。但是在msdn

随机推荐