【8.20校内测试】【DP】【二分+贪心】

一开始想的贪心,可是发现贪心的问题太多了啊!只能保证当前最优,全局完全无法考虑。
所以正解是dp。预处理出前缀和,枚举每个区间,在每个点记录$now[i]$表示以$i$这个塔结尾的塔组目前的高度。$dp[i]$表示以$i$这个塔结尾最多能分成多少组。如果$dp[i]$可以更新成更优值,则直接更新$dp$和$now$值,否则如果$dp$值相同,则尽量使$now$值最小。
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std; ll n, h[], pre[], now[], dp[]; int main ( ) {
freopen ( "tower.in", "r", stdin );
freopen ( "tower.out", "w", stdout );
scanf ( "%I64d", &n );
for ( int i = ; i <= n; i ++ )
scanf ( "%I64d", &h[i] ), pre[i] = pre[i-] + h[i];
for ( int i = ; i <= n; i ++ )
for ( int j = ; j < i; j ++ ) {
if ( pre[i] - pre[j] >= now[j] ) {
if ( dp[i] < dp[j] + ) dp[i] = dp[j] + , now[i] = pre[i] - pre[j];
else if ( dp[i] == dp[j] + ) {
now[i] = min ( now[i], pre[i] - pre[j] );
}
}
}
printf ( "%I64d", n - dp[n] );
return ;
}

显然(?)也是dp,$dp[i][j]$表示完成了$i$天,此时能力值为$j$时能做的最多工作量。$fine[i]$是预处理出的能力值为$i$时的效率最高的工作需要的时间。$qwq[i][j]$表示每个上完课后的第1天$i$,能力值为$j$,上课最短的时间。$pre[i]$表示过了$i$天可以得到的最大$dp$值。
枚举天数,能力值。
每次更新时可以选择不作为,即$dp[i][j]$直接从$dp[i-1][j]$转移过来。
如果第$i$天是某次刚上完课的第二天,则可以选择上课,从上课开始之前的最优$dp$值转移过来,即上课开始那一天的$pre$值。
如果当前天数和$fine[j]$满足可以工作,则从不工作那天转移过来,可以选择工作一次。
【注意】$dp$值初始化是负无穷,保证如果第$i$天不能满足$j$的能力值,则一定不会被更新,或去更新$pre$值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
using namespace std; int T, S, N, fine[], qwq[][], pre[], dp[][]; struct LRN {
int m, l, a;
} stdy[]; int main ( ) {
freopen ( "wrk.in", "r", stdin );
freopen ( "wrk.out", "w", stdout );
scanf ( "%d%d%d", &T, &S, &N );
memset ( qwq, 0x3f3f3f3f, sizeof ( qwq ) );
for ( RG int i = ; i <= S; i ++ ) {
int m, l, a;
scanf ( "%d%d%d", &m, &l, &a );
qwq[l+m][a] = min ( qwq[l+m][a], l );
}
memset ( fine, 0x3f3f3f3f, sizeof ( fine ) );
for ( RG int i = ; i <= N; i ++ ) {
int c, d;
scanf ( "%d%d", &c, &d );
fine[c] = min ( fine[c], d );
}
for ( int i = ; i <= ; i ++ )
fine[i] = min ( fine[i], fine[i-] );
memset ( dp, -0x3f3f3f3f, sizeof ( dp ) );
dp[][] = ;
for ( int i = ; i <= T; i ++ ) {
for ( int j = ; j <= ; j ++ ) {
dp[i][j] = dp[i-][j];
if ( qwq[i][j] != 0x3f3f3f3f ) dp[i][j] = max ( dp[i][j], pre[i-qwq[i][j]] );
if ( i - fine[j] >= ) dp[i][j] = max ( dp[i][j], dp[i-fine[j]][j] + );
pre[i] = max ( dp[i][j], pre[i] );
}
}
printf ( "%d", pre[T] );
return ;
}

很有趣的一道题。题目给出的性质是只有一个点的度数大于等于3,先找出这个点作为root。
bfs预处理出点距离的邻接矩阵,二分答案,每次去check的时候是选择root周围可以覆盖它的点,割掉这个点去更新答案。设当前枚举的点是$x$,先标记$x$可以覆盖的所有点,再dfs去计算没有被标记的点的数量,就是被拆分开的一条条链上的点的数量,每条链上需要的树洞是$ceil ( \frac{1.0 * now}{2*len+1} )$,$now$是这条链上的点数,注意因为自己也会算进去,所以一个点能覆盖的点数是$2*len+1$。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std; int n, m, k, root;
int dis[][], d[]; int stot, tov[], nex[], h[];
void add ( int u, int v ) {
tov[++stot] = v;
nex[stot] = h[u];
h[u] = stot;
} queue < int > q;
void bfs ( int s ) {
queue < int > q; q.push ( s );
while ( !q.empty ( ) ) {
int x = q.front ( ); q.pop ( );
for ( int i = h[x]; i; i = nex[i] ) {
int v = tov[i]; d[x] ++; d[v] ++;
if ( !dis[s][v] && v != s )
dis[s][v] = dis[s][x] + , q.push ( v );
}
}
} int now, v[]; void dfs ( int u ) {
now += ( v[u] = );
for ( int i = h[u]; i; i = nex[i] )
if ( !v[tov[i]] )
dfs ( tov[i] );
} int work ( int x, int len ) {
int s = ;
memset ( v, , sizeof ( v ) );
for ( int i = ; i <= n; i ++ )
v[i] = ( dis[i][x] <= len );
for ( int i = ; i <= n; i ++ )
if ( !v[i] ) now = , dfs ( i ), s += ceil ( 1.0 * now / ( * len + ) );
return s;
} bool check ( int x ) {
int ans = 0x3f3f3f3f;
for ( int i = ; i <= n; i ++ )
if ( dis[root][i] <= x ) {
ans = min ( ans, work ( i, x ) );
}
return ans < k;
} int main ( ) {
freopen ( "holes.in", "r", stdin );
freopen ( "holes.out", "w", stdout );
scanf ( "%d%d%d", &n, &m, &k );
for ( int i = ; i <= m; i ++ ) {
int x, y;
scanf ( "%d%d", &x, &y );
add ( x, y ); add ( y, x );
}
for ( int i = ; i <= n; i ++ ) {
bfs ( i );
if ( d[i] > ) root = i;
}
if ( !root ) {
cout << ceil ( 1.0 * ( n - k ) / ( k << ) );
return ;
}
int l = , r = n, ans;
while ( l <= r ) {
int mid = ( l + r ) >> ;
if ( check ( mid ) ) r = mid - , ans = mid;
else l = mid + ;
}
cout << ans;
return ;
}
【8.20校内测试】【DP】【二分+贪心】的更多相关文章
- 【8.23校内测试】【贪心】【线段树优化DP】
$m$的数据范围看起来非常有问题??仔细多列几个例子可以发现,在$m<=5$的时候,只要找到有两行状态按位$&$起来等于$0$,就是可行方案,如果没有就不行. #include<i ...
- 2019.6.20 校内测试 NOIP模拟 Day 1 分析+题解
这次是zay神仙给我们出的NOIP模拟题,不得不说好难啊QwQ,又倒数了~ T1 大美江湖 这个题是一个简单的模拟题. ----zay 唯一的坑点就是打怪的时候计算向上取整时,如果用ceil函数一 ...
- 【8.30校内测试】【找规律模拟】【DP】【二分+贪心】
对于和规律或者数学有关的题真的束手无策啊QAQ 首先发现两个性质: 1.不管中间怎么碰撞,所有蚂蚁的相对位置不会改变,即后面的蚂蚁不会超过前面的蚂蚁或者落后更后面的蚂蚁. 2.因为所有蚂蚁速度一样,不 ...
- 两种解法-树形dp+二分+单调队列(或RMQ)-hdu-4123-Bob’s Race
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4123 题目大意: 给一棵树,n个节点,每条边有个权值,从每个点i出发有个不经过自己走过的点的最远距离 ...
- 【bzoj3312】[Usaco2013 Nov]No Change 状态压缩dp+二分
题目描述 Farmer John is at the market to purchase supplies for his farm. He has in his pocket K coins (1 ...
- HDU-3681-Prison Break(BFS+状压DP+二分)
Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one da ...
- 1. 线性DP 887. 鸡蛋掉落 (DP+二分)
887. 鸡蛋掉落 (DP+二分) https://leetcode-cn.com/problems/super-egg-drop/ /*首先分析1个蛋,1个蛋的话,最坏情况需要N次,每次只能从0 1 ...
- HDU 3433 (DP + 二分) A Task Process
题意: 有n个员工,每个员工完成一件A任务和一件B任务的时间给出,问要完成x件A任务y件B任务所需的最短时间是多少 思路: DP + 二分我也是第一次见到,这个我只能说太难想了,根本想不到. dp[i ...
- Codeforces Gym 100231B Intervals 线段树+二分+贪心
Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...
随机推荐
- Daily Report-1126
今日: 上午主要是回顾了react,阅读官方文档的时候发现了list中key值设计的必要性. 看了部分react源码,发现有些吃力,在询问羽牧学长之后调整策略,从redux和mobx入手,先多熟悉用法 ...
- windows7下安装配置phonegap3.0 (cordavo)开发环境 (涉及android sdk配置)
之前在mac上安装调试过phonegap,现在公司用的是windows7,所以不得不再进行一次windows下的配置工作,顺便也写下来了 主要麻烦的地方是要在win7下添加好几个环境变量,这一块地方特 ...
- C - Contest Setting Gym - 101982C dp 补题
题目链接:https://vjudge.net/contest/273260#problem/C 学习了一下别人的思路,首先去重,然后离散化. dp数组开二维,每一次更新,状态转移方程,dp[ i ] ...
- IIS7.5 配置应用程序初始化功能
IIS进程回收后,第一次访问会超级慢,这对于用户是不能接受的,怎么解决这个问题? 我们不能设置IIS不回收进程,因为这样可能会导致IIS内存泄漏.有效的方法时,尽量在业务空闲时间回收进程,回收后立刻预 ...
- MySQL指定使用某个索引查询语句
查询语句查询emp_no,所以先查询emp_no的索引使用primary select emp_no,salary from salaries use index(s_f_t) where emp_n ...
- screen命令使用方法【转】
在linux的环境中,我们想要在后台持续运行一些脚本,但是又因为关闭这个tty的话,脚本就会中断,这个时候我们就需要screen这个工具的帮助啦! 基础 1 首先先查看下否则有这个工具.如果运行s ...
- oracle中的符号含义
1.Oracle数据库存储过程中:=是什么意思?答:赋值的意思.举例:str := 'abcd';将字符串abcd赋值给变量str. 2.oracle 存储过程中的 := 和=有什么区别?答::= 是 ...
- 6.Python3标准库--数学运算
''' 作为一种通用的变成语言,Python经常用来解决数学问题.它包含一些用于管理整数和浮点数的内置类型,这很适合完成一般应用中可能出现的基本数学运算. 而标准库中包含一些用于满足更高级需求的模块. ...
- Eloqument 学习
参考地址:https://d.laravel-china.org/docs/5.5/eloquent#mass-assignment
- Flyweight模式(亨元模式)
这应该算是最好理解的一个设计模式了吧·················· 面向对象语言的原则就是一切都是对象,但是如果真正使用起来,有时对象数可能显得很庞大,比如,字处理软件,如果以每个文字都作为一个 ...