2016 10 28考试 dp 乱搞 树状数组
#2016 10 28 考试
####时间 7:50 AM to 11:15 AM
下载链接:
这次考试对自己的表现非常不满意!!
T1看出来是dp题目,但是在考试过程中并没有推出转移方程,考虑了打表,但是发现暴力程序的速度不够,直接交了暴力,没想到暴力程序爆0,考试后仔细查找发现是在深搜过程中的一个剪枝处忘记调整全局变量的值,,,低级错误要引以为戒!!
for (int i = 0; i <= cur; i++) {
a[x] += i;
if (a[x] < a[x-1]) {
a[x] -= i; // 考试时此处直接写成了continue,忘记还原a数组
continue;
}
dfs(x + 1, cur - i);
a[x] -= i;
}
T2乱搞题,考试时连样例都没过,但是,输出时忘记写("Case"),,虽然结果都是零分,但是这种低级错误不能容忍!!
T3送分题,想出来了是树状数组,但是还是被最后三个点卡了读入常数。。Pascal直接写read就能A,然而C++的scanf就被卡了常数,,改成手写读入后AC,收了一个教训,当数据量较大时要考虑手写读入
官方题解:
a:
看到200的数据范围,看到个数和总和的范围的限制,我想所有人都会想到dp吧。。。
但是他说能凑成1~M的所有数字,这个略难满足
我们来看一个结论 假设我们选出的数字从小到大排序后,是a[], sum[]为a的前缀和
那么只要sum[N] = M 而且 a[i + 1] <= sum[i] + 1 那么就能满足1~M的所有数字
证明
充分性
可以数学归纳法证明
首先第一项a[1]必然等于1 他能凑成1~sum[1]的所有数字
假设前i项能组成sum[i]的所有数字,那么加上第i+1项后就能凑出a[i + 1] ~ a[i + 1] + sum[i]
因为a[i+ 1] <= sum[i] + 1 所以可以凑出1~a[i + 1] + sum[i] 也就是 1~sum[i+1]
必要性
可以想到如果不满足,那么起码sum[i] + 1就不能凑出来
这样就可以DP了
用f[i][j][k]代表前i个数字,和为j,是用小于等于k的数字凑出来的 即可
空间限制就用滚动数组吧
b:
如果只是单纯想如何组织这些边去形成一个方差最小的生成树,那是很困难的,至少我没有什么很好的解决办法
但是如果我们假定知道了平均值,想得出一个方差最小的生成树呢?
显然,边权尽量靠近平均值即可,而又要是棵树,那么明显只要用我们最常用的求最小生成树的方法即可.
那么平均值就可以直接枚举了,注意算出是哪些边之后要重新算出平均值
如果直接暴力枚举,时间复杂度是O(N*50*MlogM) 其中,N*M是平均值的个数。
可以发现这样可能超时
MlogM的最小生成树的算法已经无法再降,我们考虑平均值的枚举
首先一个很重要的条件,权值都是整数,那么如果你枚举的平均值x在[p, p+1]中,那么其实只有p.25 和 p.75 是需要枚举的
(自己想想为什么)
那么复杂度就是50*MlogM
c:
送分树状数组
把一个牌后面去就在最后加1,之前的位置减1,问她前面有多少人直接求前缀和吧
解题报告:
T3:
树状数组裸题,数组a记录每个人当前所在的位置,数组C为0/1数组记录当前位置是否有人,利用树状数组维护前缀和,每次查询直接查询前缀和,每次修改x时先change当前位置-1,change目标位置+1,再修改a数组更新x的位置。注意数组大小
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 4000500;
int a[maxn]; // a[x] the cur location of x
int c[maxn];
int tot;
int n, m;
int k;
int x;
char s;
inline int lowbit(int x) {
return (x & (-x));
}
void change(int x, int z) {
while (x <= k) {
c[x] += z;
x = x + (x & (-x));
}
}
int xfind(int x) {
int ans = 0;
while (x > 0) {
ans += c[x];
x = x - (x & (-x));
}
return (ans);
}
int readint(void) {
s = getchar();
while (s < '0' && s > '9') s = getchar();
int x;
while (s >= '0' && s <= '9') {
x = x * 10;
x += (int) (s - '0');
s = getchar();
}
return x;
}
int main () {
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
n = readint();
m = readint();
k = n + m;
for (int i = 1; i <= n; i++) {
a[i] = n - i + 1;
change(i, 1);
}
tot = n;
for (int i = 1; i <= m; i++) {
x = readint();
printf("%d\n", n - xfind(a[x]));
change(a[x], -1);
tot++;
a[x] = tot;
change(a[x], 1);
}
return 0;
}
T1:
dp题目(最近为什么这么多dp题目)首先考虑一个性质
假设当前已经选择了i-1个砝码,它们能够满足题意的最大质量为j,那么对于第i个砝码,其质量为a[i],如果a[i] <= j + 1,显然它能够达到j + a[i],(可以尝试举个栗子验证),而反之如果a[i] > j显然j + 1就已经不能满足。由此可推得转移时保证合法性的条件
设dp[i][j][k]表示当前取到第i个砝码,当前的最大满足条件为j,当前的最大砝码为k,
dp[i][j][k] = dp[i][j][k-1] + dp[i-1][j-k][k] (当i,j,k满足题意时)
貌似出题人是打算卡一下空间放滚动数组,不过,,好像并没有用上,,
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 200 + 10;
const long long mod = 4294967296ll;
long long dp[maxn][maxn][maxn];
int T;
bool check(int i, int j, int k) {
if (k > (j - i + 1)) return 1;
if (j % 2 == 1) j = (j >> 1) + 1;
else j = j >> 1;
if (k > j) return 1;
return 0;
}
int main () {
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
scanf("%d", &T);
for (int i = 1; i <= 200; i++)
dp[1][1][i] = 1;
for (int i = 2; i <= 200; i++)
for (int j = 2; j <= 200; j++) {
if (i > j) continue;
for (int k = 1; k <= 200; k++) {
dp[i][j][k] = dp[i][j][k-1];
if (check(i, j, k)) continue;
dp[i][j][k] = (dp[i][j][k] + dp[i-1][j-k][k]) % mod;
}
}
int n, m;
while (T--) {
scanf("%d %d", &n, &m);
printf("%I64d\n", (dp[n][m][m] % mod + mod) % mod);
}
return 0;
}
T2
乱搞题,题目中要求求方差最小的生成树,看起来比较无从下手,那么结合方差的性质可知,如果加入的边边权差尽量小,方差一定相应变小,这样就将方差问题转化为排序问题。之后考虑题目的数据范围,可以发现题目中的边的边权均较小,由此可以直接枚举平均值,每次按照abs(p[x].val - w_average)来排序,加入直到形成生成树,求出此时方差并更新答案。
注意,由于枚举平均值可能带来的精度问题,建议转而枚举边的总值
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdlib>
const int maxn = 1000 + 10;
const int maxm = 10000 + 10;
struct data {
int from;
int to;
int val;
};
data p[maxm];
int tim;
int n, m;
int minw, maxw;
bool flag[maxn];
double t_average;
double fc;
double ans = 0x7fffffff;
int father[maxn];
int getfather(int x) {
if (father[x] == x) return (x);
return (father[x] = getfather(father[x]));
}
bool cmp1 (data aa, data bb) {
return (aa.val < bb.val);
}
bool cmp2(data aa, data bb) {
double a1 = (double) aa.val;
double a2 = (double) bb.val;
a1 = fabs(a1 - t_average);
a2 = fabs(a2 - t_average);
return (a1 < a2);
}
int main () {
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
while (scanf("%d %d", &n, &m) == 2 && n && m) {
tim++;
printf("Case %d: ", tim);
for (int i = 1; i <= m; i++) scanf("%d %d %d", &p[i].from, &p[i].to, &p[i].val);
std :: sort(p + 1, p + m + 1, cmp1);
for (int i = 1; i < n; i++) {
minw += p[i].val;
maxw += p[m - i + 1].val;
}
for (int k = minw; k <= maxw; k++) {
memset(flag, 0, sizeof(flag));
for (int j = 1; j <= n; j++ ) father[j] = j;
t_average = (double) k / (double) (n-1);
std :: sort(p + 1, p + m + 1, cmp2);
int t_sumw = 0;
for (int i = 1; i <= m; i++) {
int fx = getfather(p[i].from);
int fy = getfather(p[i].to);
if (fx != fy) {
father[fx] = fy;
flag[i] = 1;
t_sumw += p[i].val;
}
}
if (t_sumw == k) {
fc = 0;
for (int i = 1; i <= m; i++)
if (flag[i]) fc += ((double)p[i].val - t_average) * ((double)p[i].val - t_average);
if (fc < ans) ans = fc;
}
}
ans = ans / (double) (n-1);
printf("%.2lf\n", ans);
}
}
2016 10 28考试 dp 乱搞 树状数组的更多相关文章
- HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca
Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...
- 【题解】ARC101F Robots and Exits(DP转格路+树状数组优化DP)
[题解]ARC101F Robots and Exits(DP转格路+树状数组优化DP) 先删去所有只能进入一个洞的机器人,这对答案没有贡献 考虑一个机器人只能进入两个洞,且真正的限制条件是操作的前缀 ...
- [BZOJ2244]:拦截导弹(DP+CDQ分治+树状数组)
题目传送门 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于 ...
- 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)
题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...
- 2016北京网络赛 hihocoder 1391 Countries 树状数组
Countries 描述 There are two antagonistic countries, country A and country B. They are in a war, and ...
- CodeForces 602E【概率DP】【树状数组优化】
题意:有n个人进行m次比赛,每次比赛有一个排名,最后的排名是把所有排名都加起来然后找到比自己的分数绝对小的人数加一就是最终排名. 给了其中一个人的所有比赛的名次.求这个人最终排名的期望. 思路: 渣渣 ...
- HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...
- bzoj4361:isn(dp+容斥+树状数组)
题面 darkbzoj 题解 \(g[i]\)表示长度为\(i\)的非降序列的个数 那么, \[ ans = \sum_{i=1}^{n}g[i]*(n-i)!-g[i+1]*(n-i-1)!*(i+ ...
- hdu6078 Wavel Sequence dp+二维树状数组
//#pragma comment(linker, "/STACK:102400000,102400000") /** 题目:hdu6078 Wavel Sequence 链接:h ...
随机推荐
- http协议区分头信息和正文
http协议中的头信息和正文是採用空行分开,什么是空行呢?简单来说,就是\r\n\r\n. 所以将server返回的数据用\r\n\r\n分开后的结果,一个是头信息.一个是正文信息. C#的代码例如以 ...
- byte类型取值范围以及溢出具体解释
例1: public class test { public static void main(String[] args) { byte a = 127 ; a = (byte)(a+3) ; Sy ...
- (十进制高速幂+矩阵优化)BZOJ 3240 3240: [Noi2013]矩阵游戏
题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=3240 3240: [Noi2013]矩阵游戏 Time Limit: 10 Sec M ...
- Linux系统编程——进程替换:exec 函数族
在 Windows 平台下,我们能够通过双击运行可运行程序,让这个可运行程序成为一个进程.而在 Linux 平台.我们能够通过 ./ 运行,让一个可运行程序成为一个进程. 可是.假设我们本来就执行着一 ...
- 一个操作oracle的c#类 含分页
有别于以前的一个OracleHelper,这个版各有所长,MARK下. using System; using System.Data; using System.Data.OracleClient; ...
- 关于HTML与CSS与class
在web前端开发中接触的一直是html.css.javascript. 在这个过程中,经常使用的是html中的span.div元素以及css的选择器. 为了方便查找在这里将这些内容的基础知识记录下来. ...
- [转]数据库事务中的隔离级别和锁+spring Transactional注解
数据库事务中的隔离级别和锁 数据库事务在后端开发中占非常重要的地位,如何确保数据读取的正确性.安全性也是我们需要研究的问题.ACID首先总结一下数据库事务正确执行的四个要素(ACID): 原子性(At ...
- JavaScript中闭包的理解
1.什么是闭包 我个人理解闭包就是函数中嵌套函数,但是嵌套的那个函数必须是返回值,才构成闭包: <!DOCTYPE html> <html> <head> < ...
- layer.js漂亮的弹出框
它的官方网站:http://layer.layui.com/ 消息.确认框.ifame.自定义文本.旋转木马,都有按钮,是一款强大的js 弹出框: 以下为本人的简单介绍: layer.open({ t ...
- [转自百度贴吧-本人亲测有效]Adobe XD 打开立即闪退问题修复
出现闪退的原因还是因为缺少C++组件, 下载 DirectXRepairV3.7软件 原文: https://tieba.baidu.com/p/5961511474 软件下载: http://xia ...