首页 > 其他分享 >UOJ918 【UR #28】偷吃蛋糕 题解

UOJ918 【UR #28】偷吃蛋糕 题解

时间:2024-11-19 11:45:58浏览次数:1  
标签:UOJ918 le int 题解 28 ge maxn 蛋糕 res

题目描述

\(n\) 层蛋糕,第 \(i\) 层大小 \(c_i\) ,保证 \(c_i\) 单调不增。

初始你有第 \(1\) 层蛋糕,然后重复以下操作,直至没有蛋糕:

  • 吃掉最大的一层蛋糕,记其大小为 \(x\) 。
  • 如果还有至少 \(x\) 层蛋糕没有给你,主办方会按编号升序给你接下来的 \(x\) 层蛋糕。
  • 如果只有 \(y\) 层蛋糕(\(y\lt x\)),主办方会给你全部蛋糕,同时可以获得 \(x-y\) 的收益。
  • 每次主办方给你蛋糕时(假设要给你 \(x\) 层),老鼠会从这 \(x\) 层蛋糕等概率随机偷走一层蛋糕,你可以获得剩余 \(x-1\) 层蛋糕。

求收益的期望值对 \(998244353\) 取模的结果。

数据范围

  • \(1\le n\le 2000\) 。
  • \(1\le c_i\le n\) , \(c_i\) 单调不增。

分析

首先分析如何描述一个状态,你已经获得了前若干层蛋糕,然后你有一串尚未使用的 \(c_i\) 序列。每次用掉序列开头的 \(c_i\) ,然后在序列末尾加入 \(c_i-1\) 个数。

因此你要有一点直觉,这题不是正经的动态规划,因为状态实在过于复杂。

接下来是人类智慧搜索剪枝。

由于我们只会在末尾添加 \(c_i\) ,因此接下来的 \(|\text{seq}|\) 步操作仅由序列中已知的 \(c_i\) 确定。如果仅通过这些 \(c_i\) 就可以确保让主办方给你全部蛋糕,我们可以在 \(O(n)\) 的时间内计算贡献。

具体的,如果可以确保主办方给你全部蛋糕(有做不到的情况,参见样例一),那么你的收益为你获得的 \(c_i\) 之和减去 \(n-1\) 。

假如 \(S=\sum\limits_{\text{used}}c_i+\sum\limits_{\text{in seq}}c_i\ge n\) ,扫描序列中的每个 \(c_i\) (模拟接下来的每一步操作——给你第 \(l\sim r\) 层蛋糕),这一步期望贡献 \(\frac{r-l}{r-l+1}\sum_{j=l}^rc_j\) 。


如果 \(c_i\) 很大,直觉告诉你 \(S\ge n\) 很快就会成立。

那到底快到什么程度呢?

记 \(m=\lceil\sqrt n\rceil\) ,如果 \(c_{c_1+1}\ge m\) ,那么 \(c_1\ge\cdots\ge c_{c_1+1}\ge m\) ,第一步操作后 \(S\gt c_1\cdot c_{c_1+1}\ge m^2\ge n\) ,一步就结束了。

因此如果一步没有结束,那么从第二步起在序列中添加的数都满足 \(c_i\lt m\le 45\) ,换言之 \(c_i\) 非常稠密。

于是容易想到另外一个强有力的剪枝。老鼠偷走相同的 \(c_i\) 本质上没有区别,我们只需要搜索一次,然后乘上相应概率。

这样一个状态的子状态个数为区间(这一步给你的蛋糕)中不同 \(c_i\) 的个数。定义势能 \(\varphi\) 为尚未给你的 \(c_i\) 最大值,假设当前状态有 \(x\) 个子状态,那么这些子状态的势能都至少减少 \(x-1\) 。

最坏情况下每次 \(x=2\) ,则 \(\varphi(n)=2^n\) 。理论状态上限为 \(n\cdot\varphi(\sqrt n)\) ,但实际根本卡不满,而且跑得飞快。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2005,mod=998244353;
int n;
int c[maxn],s[maxn],inv[maxn],fir[maxn],lst[maxn];
bool vis[maxn];///记录每层蛋糕是否被偷走
int qpow(int a,int k)
{
    int res=1;
    for(;k;a=1ll*a*a%mod,k>>=1) if(k&1) res=1ll*res*a%mod;
    return res;
}
int dfs(int d,int s1,int s2)
{///正在吃第 d 层蛋糕,已经用过的 c_i 之和为 s1 ,已经用过 & 序列中的 c_i 之和为 s2
    if(s2+1>=n)
    {
        int res=s2-(n-1);
        for(int l=s1+1+1,r=0;l<=n;l=r+1,d++)
        {
            while(d<=n&&vis[d]) d++;
            assert(d!=n+1),r=min(l+c[d]-1,n);
            res=(res+(mod+1ll-inv[r-l+1])*(s[r]-s[l-1]))%mod;
        }
        return res;
    }
    while(d<=n&&vis[d]) d++;
    if(d==n+1) return 0;
    int l=s1+1+1,r=s1+1+c[d],res=0,sum=s[r]-s[l-1];///主办方给你第 [l,r] 层
    assert(r<=n);
    for(int j=c[l];j>=c[r];j--)
    {///尝试偷吃 c_i=j 的蛋糕
        if(!lst[j]) continue;
        vis[max(l,fir[j])]=1;
        res=(res+(min(r,lst[j])-max(l,fir[j])+1ll)*dfs(d+1,s1+c[d],s2+sum-j))%mod;
        vis[max(l,fir[j])]=0;
    }
    return 1ll*res*inv[c[d]]%mod;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&c[i]),s[i]=s[i-1]+c[i],inv[i]=qpow(i,mod-2),lst[c[i]]=i;
        if(!fir[c[i]]) fir[c[i]]=i;
    }
    printf("%d\n",dfs(1,0,c[1]));
    return 0;
}

标签:UOJ918,le,int,题解,28,ge,maxn,蛋糕,res
From: https://www.cnblogs.com/peiwenjun/p/18554556

相关文章

  • C -- [vs2019] C2440 错误,无法从 const char[] 转换为 char*问题解决
    https://blog.csdn.net/weixin_45525272/article/details/118699716原因新标准中,不能把指针指向一串常量解决方案一:引入[]char*str=“helloworld”;改成:charstr_tmp[]=“helloworld”;char*str=str_tmp;方案二:加constchar*str=“helloworld”;改成:......
  • ABC380 DEFG 题解
    ABC380题解赛时秒了ABCDE(好吧其实还是略有卡顿,写完大概花了55min),看到F有博弈直接跑了,没注意到数据范围这么小,看到G一下就会了大致思路,但具体细节上搞复杂了,快写完了才发现不用维护这么多(恼),然后因为某些神秘错误现在都还没有调出来。至于F,赛后看见数据范围这么小,自己独立......
  • マス目と整数 题解
    前言题目链接:洛谷;AtCoder。题意简述给你一个\(n\timesm\)的矩形\(a\),其中已经有\(q\)个位置填上了数,你需要为剩下的位置分别填上一个非负整数,使得最终任意一个\(2\times2\)的子矩形内,左上角的数加右下角的数等于右上角的数加左下角的数,即\(\foralli\in[1,n),j\in......
  • 9.28
    在Android应用开发过程中,安全问题不容忽视。随着应用用户量的增长,应用面临的威胁和攻击也在不断增加。本文将介绍Android应用可能面临的一些常见威胁,以及如何采取措施来防范这些威胁。一、恶意代码注入恶意代码注入是一种攻击方式,攻击者通过修改应用代码或插入恶意代码来获取用......
  • 力扣2228-7天内两次购买的用户
    一、数据源2228.7天内两次购买的用户表: Purchases+---------------+------+|ColumnName|Type|+---------------+------+|purchase_id|int||user_id|int||purchase_date|date|+---------------+------+purchase_id包含唯一值。该......
  • CF715B Complete The Graph 题解
    Description给\(n\)点\(m\)边的无向图,\(L\),\(s\),\(t\)。修改\(m\)条边中边为\(0\)的边,使满足\(s,t\)的最短路长度是\(L\),且输出答案的时候边为\(0\)的边的权值必须在\([1,10^{18}]\)内。Solution考虑怎么判有无解。容易发现将所有未知边边权设为\(10^{18}\),......
  • ZZJC新生训练赛第17场题解
    难度分类(同一难度下按字典序上升)入门:J简单:G,E,D中等:I,B,k困难:F,AJ-解题思路按照题意模拟即可J-代码实现for_inrange(int(input())):print(int(int(input())**0.5))G-解题思路dp入门题跳台阶小改G-代码实现MOD=int(1e9+7)dp=[0]*in......
  • Codeforces Round 988 (Div. 3) E题解析
    E题题目链接CodeforcesRound988(Div.3)题目描述题目的思路根据题目的意思,我们可以推断出算法时间复杂度应该在O(N)对于这道题而言,我们可以分析下思路首先我们先从1~n的范围里面询问答案如果出现0就跳过,因为无序操作如果出现非0答案temp就记录下1~i的01序列的个数如果......
  • [HCTF 2018]Warmup 详细题解
    知识点:目录穿越_文件包含static静态方法参数传递引用mb_strpos函数    mb_substr函数正文:页面有一张滑稽的表情包,查看一下页面源代码,发现提示那就访问/source.php 得到源码<?phphighlight_file(__FILE__);classemmm{publics......
  • CF1499D The Number of Pairs 题解 线性筛
    题目链接:https://codeforces.com/problemset/problem/1499/D题目大意:给你三个整数\(c,d,x\)(\(1\lec,d,x\le10^7\)),问:存在多少对正整数对\((a,b)\)满足:\[c\cdotlcm(a,b)-d\cdotgcd(a,b)=x\]其中,\(lcm(a,b)\)表示整数\(a\)和\(b\)的最大公约数,\(gcd(a,......