Bzoj4899--记忆的轮廓

Description

通往贤者之塔的路上,有许多的危机。

我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,

在[1,n]中,一共有n个节点。我们把编号在[1,n]的叫做正确节点,[n+1,m]的叫做错误节点。一个叶子,如果是正

确节点则为正确叶子,否则称为错误叶子。莎缇拉要帮助昴到达贤者之塔,因此现在面临着存档位置设定的问题。

为了让昴成长为英雄,因此一共只有p次存档的机会,其中1和n必须存档。被莎缇拉设置为要存档的节点称为存档

位置。当然不能让昴陷入死循环,所以存档只能在正确节点上进行,而且同一个节点不能存多次档。因为通往贤者

之塔的路上有影响的瘴气,因此莎缇拉假设昴每次位于树上一个节点时,都会等概率选择一个儿子走下去。每当走

到一个错误叶子时,再走一步就会读档。具体的,每次昴到达一个新的存档位置,存档点便会更新为这个位置(假

如现在的存档点是i,现在走到了一个存档位置j>i,那么存档点便会更新为j)。读档的意思就是回到当前存档点

。初始昴位于1,当昴走到正确节点n时,便结束了路程。莎缇拉想知道,最优情况下,昴结束路程的期望步数是多

少?

Input

第一行一个正整数T表示数据组数。

接下来每组数据,首先读入三个正整数n,m,p。

接下来m-n行,描述树上所有的非正确边(正确边即连接两个正确节点的边)

用两个正整数j,k表示j与k之间有一条连边,j和k可以均为错误节点,也可以一个为正确节点另一个为错误节点。

数据保证j是k的父亲。

50<=p<=n<=700,m<=1500,T<=5。

数据保证每个正确节点均有至少2个儿子,至多3个儿子。

Output

T行每行一个实数表示每组数据的答案。请保留四位小数。

--------------------------------------此后一千里-------------------------------------------------

题解 :

首先我们设v[i][j]表示前一个存档点为 i ,走到 j 的期望步数。这个可以递推求得。

然后最优解就可以表示为v[1][a1]+v[a1][a2]+...+v[ap][n]

所以最优解可以dp得到。直接dp是n^3的,可能跑不过,观察发现由于题目性质,v[i][j]至少是v[i][j-1]的两倍,

而p大于等于50,所以v[i][i+16]及之后的值都过大,所以我们只用管前16个就可以了。

代码 :

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define LL long long
using namespace std;

#define int int
inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}
inline int Sqr(int a) {return a*a;}
inline int Abs(int a) {return a>0?a:-a;}
#undef int

#define MAXN 705

struct Edge{
    int to,next;
}e[MAXN*5];int head[1505],cnt;
inline void Insert(int a,int b) {
    e[++cnt].next=head[a];head[a]=cnt;e[cnt].to=b;
}

double v[MAXN][MAXN],r[1505],E[1505],dp[MAXN][MAXN];
int n,m,p,T;

void Dp(int v) {
    E[v]=0;
    for(int i=head[v];i;i=e[i].next) {
        Dp(e[i].to);E[v]+=E[e[i].to];
    }
    if(r[v]) E[v]/=r[v];
    E[v]++;
}

int main() {
    scanf("%d",&T);
    while(T--) {
        memset(head,0,sizeof(head));cnt=0;
        memset(r,0,sizeof(r));
        scanf("%d%d%d",&n,&m,&p);p--;
        for(int a,b,i=n+1;i<=m;i++) {
            scanf("%d%d",&a,&b);
            Insert(a,b);r[a]++;
        }
        for(int i=1;i<n;i++) r[i]++;
        for(int i=1;i<=n;i++) {
            E[i]=0;
            for(int j=head[i];j;j=e[j].next) {
                Dp(e[j].to);E[i]+=E[e[j].to];
            }
        }
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++) {
                if(i-j>16) break;
                v[i][j]=E[j-1]+r[j-1]+r[j-1]*v[i][j-1];
            }
        for(int i=1;i<=n;i++) for(int j=0;j<=p;j++) dp[i][j]=1e20;
        dp[n][0]=0;
        for(int i=n;i;i--)
            for(int j=1;j<=p;j++)
                for(int k=i+1;k<=n;k++) {
                    if(k-i>16) break;
                    dp[i][j]=min(dp[i][j],v[i][k]+dp[k][j-1]);
                }
        printf("%.4lf\n",dp[1][p]);
    }
    return 0;
}

时间: 2024-08-24 15:19:50

Bzoj4899--记忆的轮廓的相关文章

bzoj 4899 记忆的轮廓 题解(概率dp+决策单调性优化)

题目背景 四次死亡轮回后,昴终于到达了贤者之塔,当代贤者夏乌拉一见到昴就上前抱住了昴“师傅!你终于回来了!你有着和师傅一样的魔女的余香,肯定是师傅”.众所周知,大贤者是嫉妒魔女沙提拉的老公,400年前与神龙.剑圣一起封印魔女因子暴走的莎缇拉.在魔女茶会的时候,莎缇拉也表示过对昴浓浓的爱意,昴便是被莎缇拉召唤来异世界的.而贤者之塔中的资料与试炼,似乎都指向同一种可能性……记忆的轮廓,逐渐显形…… 题目描述 通往贤者之塔的路上,有许多的危机.我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编

loj6171/bzoj4899 记忆的轮廊(期望dp+优化)

题目: https://loj.ac/problem/6171 分析: 设dp[i][j]表示从第i个点出发(正确节点),还可以有j个存档点(在i点使用一个存档机会),走到终点n的期望步数 那么 a[i][k]表示i点为存档点,从i点走到k点(正确节点)的期望步数(中间没有其它存档点) 那么a[i][j]可以递推预处理出 其中g[v]表示从一个错误节点v开始走,期望走g[v]步会读档 解方程可以解出 s[j-1]就是点j-1出去的所有错误儿子的g[v]之和 那么接下来只要知道如何求g[v]就行了

考后反思(bzoj3940 bzoj4899 bzoj3307)

考试的时候用哈希水过了第一题本来想用哈希只可以得20左右没想到由于数据过于水A了 然后雨天的尾巴骗了5分,总分105 我太菜了 首先时间分配的不合理:第一题大水题ac自动机打完了都不会,第二题略微想了想打了个高斯消元,然后样例没过......,最后输出了一个随机数,第三题(lca板子忘了,打错一个地方,没有调出来)最后骗了五分 考后主要讲一下第二题:记忆的轮廓(bzoj4899)和第三题:雨天的尾(yi)巴(bzoj3307) Censoring FJ把杂志上所有的文章摘抄了下来并把它变成了一个

致我们终将逝去的青春

致我们终将逝去的青春 踩着素白的雾霭起步,晨曦的彩霞落寞地逼向幻想,沿着夕阳殊途的文脉,光阴碎落在记忆的轮廓里.让我们捡着星星的碎片,一起踏上这段追寻青春的记忆-- 冗长的雨季中,一个梦境重叠着另一个梦境.我们这群不知天高地厚的孩子,徘徊在善与恶的边缘,在侧目,在观望.谁都没有觉察到,在我们一步一步前进的同时,青春,已与我们背道而驰,渐行渐远.撩开尘封已久的心扉,那份无所依的情愫被缓缓的唤醒,在墨香紧扣里,沾一抹浅笑思故人,携一瓣心香念昨日的柔情······曾经的微笑,曾经的誓言,曾经的我们一起

2019-6-14考试总结

A. Censoring 题目描述 FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5??的字符串S.他有一个包含n个单词的列表,列表里的n个单词记为t1~t?N.他希望从S中删除这些单词.FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词.他重复这个操作直到S中没有列表里的单词为止.注意删除一个单词后可能会导致S中出现另一个列表中的单词FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现

高二一调(20190614)

T1:Censoring 和以前kmp一样的一道题,只是改成了多个串需要AC自动机 用一个栈维护当前字符串,匹配上了就暴力弹栈,并将指针回溯,复杂度O(n+m) 这题考试的时候不知道怎么把栈给否掉了,用了个玄学方法记录,只干出来13分 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define null NULL

6/14考试总结

实锤:我就是一个超级大垃圾!!! 必须从这个视角俯瞰自己了啊 T1:Censoring FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过1e5的字符串S.他有一个包含n个单词的列表,列表里的n个单词记为ti,他希望从S中删除这些单词.FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词.他重复这个操作直到S中没有列表里的单词为止.注意删除一个单词后可能会导致S中出现另一个列表中的单词FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情

梳理思路

从头开始吧 一: T1:Censoring(字符串hash) hash+灵活运用+神仙思路: jg[]表示答案串,c[]是读入串,lhash[]表示新字符串的hash值,shash[]表示原字符串的hash值 用两个指针js表示最后输出字符串的长度,zz表示原字符串加到哪了, 每从原字符串里往答案加一个新字符,就从枚举一遍n个的单词的列表看哪个单词能删,就把js-=该单词长度 删完一个就break掉,防止算重(不知道会不会) 核心代码 T2:记忆的轮廓(大神概期+DP) (1)首先,要先读懂题,

决策单调性优化dp 专题练习

决策单调性优化dp 专题练习 优化方法总结 一.斜率优化 对于形如 \(dp[i]=dp[j]+(i-j)*(i-j)\)类型的转移方程,维护一个上凸包或者下凸包,找到切点快速求解 技法: 1.单调队列 : 在保证插入和查询的x坐标均具有单调性时可以使用 2.单调栈+二分:保证插入有单调性,不保证查询有单调性 3.分治+ 1 或 2:在每次分治时将\([l,mid]\)这段区间排序后插入,然后更新右区间\([mid+1,r]\)的答案 二.分治.单调队列维护有单调性的转移 (甚至还有分治套分治)

JAVA记忆翻牌游戏制作

游戏功能需求说明 代码编写 1 框架搭建 2 主要技术难点 21 图片面板对应的图片索引获取 22 图片面板 3 完整代码 游戏截图 1启动后界面 2开始游戏界面 3游戏结束界面 1 游戏功能需求说明 该游戏主要模拟常见的翻牌游戏,即找到所有两两相同的牌认为游戏成功,主要需求包含: 初始化面板后显示所有图片网格,图片默认显示为背景色: 点击图片后显示图片,再次点击后显示背景: 点击另一张图片,如果与前一张图片相同,则两张图片一直显示,再次点击不会再显示为背景,表示配对成功:如果与前一张图片不同,