蓝书思维题
simple ones:
POJ 1236 Network of Schools
题意:一个包含1-n号学校的网络,每个学校有个软件分发列表,当学校拿到软件时会把软件分发给列表里的学校。
问1:一个新软件出现时初始化情况至少需要给多少个学校才能让它到达整个网络?
问2:至少需要添加多少个名单才能使从任意一个学校开始分发都能充满整个网络?
也就是:
—给定一个有向图,求:1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
— 顶点数<= 100
解题思路:
1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
加边的方法:
要为每个入度为0的点添加入边,为每个出度为0的点添加出边
假定有 n 个入度为0的点,m个出度为0的点,如何加边?
把所有入度为0的点编号 0,1,2,3,4 ….N -1
每次为一个编号为i的入度0点可达的出度0点,添加一条出边,连到编号为(i+1)%N 的那个出度0点,
这需要加n条边
若 m <= n,则
加了这n条边后,已经没有入度0点,则问题解决,一共加了n条边
若 m > n,则还有m-n个入度0点,则从这些点以外任取一点,和这些点都连上边,即可,这还需加m-n条边。
所以,max(m,n)就是第二个问题的解
此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加清单的项了,所以答案是1,0;
CF1060C Maximum Subrectangle
现在给出一个长度为N的a数列,一个长度为M的b数列. 现在需要构造出一个矩阵c,其中ci,j=ai×bj.再给出一个x,请在矩阵中找出一个最大的矩形,使得这个矩形中的所有值的和小于等于x.
题解:这个其实考察的就是矩阵乘法的本质,点乘
uva Zombie's Treasure Chest
你有一个体积为N的箱子和两种数量无限的宝物。宝物1的体积为S1,价值为V1:;宝物2的体积为S2,价值为V2。输入均为32位带符号整数。 计算最多能装多大价值的宝物。(每种宝物都必须拿非负整数个)。
题解:本题看似是dp中的背包问题,但是由于数据量太大,用dp肯定会超时,所以只能寻找另外一种思路,可以用贪心加暴力,先求出两种宝石大小的最小公倍数com,然后将N/com-com,与N%com看成是两个部分(想想应该明白)。将前一个部分,放入单位价值量最高的那个,对于后面那个部分直接将S1的数量从一枚举到最大的数量就可以了。(记得将除了例子数以外的数申明成longlong型的)
difficult ones:
Codeforces-696B Puzzles
题目大意:
给你一棵树,问你从根走到最后一个节点,最早到达每个节点的期望,从父亲节点到儿子节点的顺序是随机的,他到某个儿子后走完儿子子树的节点,再去其另一个儿子,直到他的子树也走完。
题解:
期望DP;
BZOJ4318-OSU! 概率DP
【题目大意】
现在这个问题变成了期望问题,那么我们只需要维护一个x 的期望和x2 的期望即可。注意平方的期望不等于期望的平方。
[SCOI2008]奖励关
题目描述
你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关。在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝物以后也不能再吃)。
宝物一共有n种,系统每次抛出这n种宝物的概率都相同且相互独立。也就是说,即使前k-1 次系统都抛出宝物1(这种情况是有可能出现的,尽管概率非常小),第k次抛出各个宝物的概率依然均为1/n。
获取第 i 种宝物将得到Pi分,但并不是每种宝物都是可以随意获取的。第i种宝物有一个前提宝物集合Si。只有当Si中所有宝物都至少吃过一次,才能吃第i 种宝物(如果系统抛出了一个目前不能吃的宝物,相当于白白的损失了一次机会)。注意,Pi 可以是负数,但如果它是很多高分宝物的前提,损失短期利益而吃掉这个负分宝物将获得更大的长期利益。
假设你采取最优策略,平均情况你一共能在奖励关得到多少分值?
输入输出格式
输入格式:
第一行为两个正整数k 和n,即宝物的数量和种类。以下n行分别描述一种
宝物,其中第一个整数代表分值,随后的整数依次代表该宝物的各个前提宝物(各
宝物编号为1到n),以0结尾。
输出格式:
输出一个实数,保留六位小数,即在最优策略下平均情况的得分。
输入输出样例
说明
1 <= k <= 100, 1 <= n <= 15,分值为[-106,106]内的整数。
题解:n<=15,状压DP,很明显;
此题最大的难度在于前面不选后面也不能选,处理这个就是:利用状态,像大部分期望dp一样倒着做,
dp[i][s]表示第i轮已经选过的种类为s的最大分数;
枚举选取的种类,如果s中含有j的全部种类,dp[i][s] = max(dp[i+1][s], dp[i+1][s|j]);
这样可以保证前面没有选过的后面也不会选;
#include <bits/stdc++.h> using namespace std; const int maxn = 4e4; int w[20],sta[maxn]; double dp[105][maxn]; int main(){ int n,k; scanf("%d%d",&k,&n); for(int i = 1; i <= n; i++){ scanf("%d",&w[i]); int pre; while(scanf("%d",&pre) == 1){ if(!pre)break; sta[i] |= (1<<(pre-1)); } } for(int i = k; i >= 1; i--) for(int s = 0; s <= (1<<n)-1; s++){ for(int j = 1; j <= n; j++){ if(sta[j] == (sta[j] & s)) dp[i][s] += max(dp[i+1][s], dp[i+1][s|(1<<(j-1))]+w[j]); else dp[i][s] += dp[i+1][s]; } dp[i][s] /= n; } printf("%.6lf",dp[1][0]); }
题意:给出范围为(0, 0)到(n, n)的整点,你站在原点处,问有多少个整点可见。
题解:对于点(x, y), 若g = gcd(x, y) > 1,则该点必被点(x/g, y/g)所挡住。
因此所见点除了(1, 0)和(0, 1)满足横纵坐标互素。
最终答案为2 * sum(phi[n]) + 3 ,其中的+3对应(1, 1) (1, 0) (0, 1)三个点