[题目链接]

铺设道路 : https://www.luogu.org/problemnew/show/P5019

货币系统 : https://www.luogu.org/problemnew/show/P5020

赛道修建 :https://www.luogu.org/problemnew/show/P5021

[题解]

       Problem A 铺设道路

       首先 , 我们有一个分治的思路 , 对于一段区间[l , r] , 最优策略为将区间内的所有数都减掉区间中的最小值 , 然后将该问题分成两个子问题 , 分治下去即可 , 时间复杂度 : O(N ^ 2)

用ST表预处理区间最小值 , 分治时实现O(1)查询 , 时间复杂度优化为 O(NlogN)

我们还可以使用贪心算法 , 如果第i个数 > 第(i - 1)个数 , 则它们对答案产生了(Hi - Hi-1)的“贡献” , 贡献相加即为答案 , 证明略 , 时间复杂度 : O(N)

Problem B 货币系统

       首先有一个结论 : 在最优的情况下 , 必然满足m为n的子集 , 这个结论是显然的

根据这个结论 , 我们不妨将a数组按升序排序 , 若第(k + 1)个数能由前k个数组合出 , 则删除第(k + 1)个数

具体实现时可以完全背包 , 时间复杂度 : O(TNW)(取W = 25000)

Problem C 赛道修建

要求长度最小的赛道长度尽可能大 , 我们不妨二分答案limit

对于以u为根节点的一棵子树 , 我们可以记录每一条连接到u的赛道的长度value , 和这条路径的长度u ,若 :

1. value + w >= limit , 将答案加一 , 单独构成一条赛道

       2. value + w < limit , 对于这种情况 , 我们将(value + w)插入到一棵平衡树(可以方便使用std :: multimap)

然后 , 对于平衡树中的每个数w , 我们贪心地将找到最小的v , 使得w + v >= limit , 并在平衡树中删除w和v

最后我们只要判断路径条数是否 >= m , 即可

时间复杂度 : O(NlogN ^ 2) , 注意优化常数 , 如二分上界可定为树的直径

[代码]

铺设道路 :

// Sprease Table O(NlogN)
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
const int MAXLOG = ; int n;
long long ans;
int a[MAXN];
int mn[MAXN][MAXLOG] , loc[MAXN][MAXLOG]; template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
template <typename T> inline void read(T &x)
{
T f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = (x << ) + (x << ) + c - '';
x *= f;
}
inline pair<int , int> query(int l , int r)
{
int k = (int)((double)log(r - l + ) / log(2.0));
int ret1 = min(mn[l][k] , mn[r - ( << k) + ][k]);
int ret2;
if (mn[l][k] < mn[r - ( << k) + ][k]) ret2 = loc[l][k];
else ret2 = loc[r - ( << k) + ][k];
return make_pair(ret1 , ret2);
}
inline void solve(int l , int r , int k)
{
if (l > r) return;
pair<int , int> tmp = query(l , r);
ans += tmp.first - k;
solve(l , tmp.second - , tmp.first);
solve(tmp.second + , r , tmp.first);
} int main()
{ read(n);
for (int i = ; i <= n; i++)
{
read(a[i]);
mn[i][] = a[i];
loc[i][] = i;
}
for (int j = ; j < MAXLOG; j++)
{
for (int i = ; i + ( << j) - <= n; i++)
{
mn[i][j] = min(mn[i][j - ] , mn[i + ( << (j - ))][j - ]);
if (mn[i][j - ] < mn[i + ( << (j - ))][j - ]) loc[i][j] = loc[i][j - ];
else loc[i][j] = loc[i + ( << (j - ))][j - ];
}
}
solve( , n , );
cout<< ans << "\n"; return ;
}

货币系统 :

#include<bits/stdc++.h>
using namespace std;
#define MAXN 110 int n;
int a[MAXN];
bool dp[]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
T f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = (x << ) + (x << ) + c - '';
x *= f;
}
int main()
{ int T;
read(T);
while (T--)
{
read(n);
for (int i = ; i <= n; i++) read(a[i]);
memset(dp , false , sizeof(dp));
dp[] = true;
int ans = ;
sort(a + , a + n + );
for (int i = ; i <= n; i++)
{
if (dp[a[i]]) continue;
++ans;
for (int j = a[i]; j <= ; j++)
{
dp[j] |= dp[j - a[i]];
}
}
printf("%d\n" , ans);
} return ; }

赛道修建 :

#include<bits/stdc++.h>
using namespace std;
#define MAXN 50010
typedef long long ll;
typedef long double ld;
const ll inf = 1e15; struct edge
{
int to , w , nxt;
} e[MAXN << ]; int n , m , tot , cnt;
int head[MAXN];
ll dist[MAXN];
multiset< ll > M[MAXN]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
T f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = (x << ) + (x << ) + c - '';
x *= f;
}
inline void addedge(int u , int v , int w)
{
++tot;
e[tot] = (edge){v , w , head[u]};
head[u] = tot;
}
inline ll dfs(int u , int father , ll limit)
{
M[u].clear();
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (v == father) continue;
ll val = dfs(v , u , limit) + (ll)w;
if (val >= limit) ++cnt;
else M[u].insert(val);
}
ll ret = ;
while (!M[u].empty())
{
if ((int)M[u].size() == )
{
chkmax(ret , *M[u].begin());
break;
} else
{
ll tmp = *M[u].begin();
M[u].erase(M[u].begin());
multiset< ll > :: iterator it = M[u].lower_bound(limit - tmp);
if (it == M[u].end())
{
chkmax(ret , tmp);
} else
{
++cnt;
M[u].erase(it);
}
}
}
return ret;
}
inline ll diameter()
{
queue< int > q;
for (int i = ; i <= n; i++) dist[i] = inf;
dist[] = ;
q.push();
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (dist[u] + w < dist[v])
{
dist[v] = dist[u] + w;
q.push(v);
}
}
}
int s = ;
for (int i = ; i <= n; i++)
if (dist[i] > dist[s]) s = i;
for (int i = ; i <= n; i++) dist[i] = inf;
dist[s] = ;
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (dist[u] + w < dist[v])
{
dist[v] = dist[u] + w;
q.push(v);
}
}
}
ll ret = ;
for (int i = ; i <= n; i++) chkmax(ret , dist[i]);
return ret;
}
inline bool check(ll mid)
{
cnt = ;
dfs( , , mid);
return cnt >= m;
} int main()
{ read(n); read(m);
ll l = , r = , ans = ;
for (int i = ; i < n; i++)
{
int u , v , w;
read(u); read(v); read(w);
addedge(u , v , w);
addedge(v , u , w);
}
r = diameter();
while (l <= r)
{
ll mid = (l + r) >> ;
if (check(mid))
{
ans = mid;
l = mid + ;
} else r = mid - ;
}
printf("%lld\n" , ans); return ; }

[NOIP 2018 Day1] 简要题解的更多相关文章

  1. A · F · O —— JLOI2018翻车记(附Day1简要题解)

    JLOI2018翻车记 并不知道该怎么写... 算了还是按照标准剧情来吧 这应该是一篇写得非常差的流水账... 2018.04.04 Day -1 省选前在机房的最后一天. 压力并不是很大,毕竟联赛 ...

  2. NOIP 2018 day1 题解

    今年noip的题和去年绝对是比较坑的题了,但是打好的话就算是普通水准也能350分以上吧. t1: 很显然这是一个简单的dp即可. #include<iostream> #include&l ...

  3. NOIP 2018 Day1

    Fei2Xue@Lian$Tian! 三道原题qwq真的凉 半年前看到有人发说说,梦见省选打开题目,是Please contact lydsy2012@163.com! 没想到一语成谶 大众分300 ...

  4. JLOI2015 DAY1 简要题解

    「JLOI2015」有意义的字符串 题意 给你 \(b, d, n\) 求 \[ [(\frac{b + \sqrt d}2)^n] \mod 7528443412579576937 \] \(0 & ...

  5. SCOI2016 Day1 简要题解

    目录 「SCOI2016」背单词 题意 题解 代码 「SCOI2016」幸运数字 题意 题解 总结 代码 「SCOI2016」萌萌哒 题意 题解 总结 代码 「SCOI2016」背单词 题意 这出题人 ...

  6. SCOI 2015 Day1 简要题解

    「SCOI2015」小凸玩矩阵 题意 一个 \(N \times M\)( $ N \leq M $ )的矩阵 $ A $,要求小凸从其中选出 $ N $ 个数,其中任意两个数字不能在同一行或同一列, ...

  7. AHOI2013 Round2 Day1 简要题解

    第一题,好吧这是个dp.(搜素也能在BZOJ上卡过). 第二题,BFS搜索碰到的立方体面数,智硬没有想到... 第三题,其实一看就有思路,但关键是求x坐标不交的矩形对数+y坐标不交的矩形对数 - x, ...

  8. noip 2018 day1 T2 货币系统 完全背包

    Code: #include<cstdio> #include<string> #include<cstring> #include<algorithm> ...

  9. noip 2018 day1 T3 赛道修建 贪心_树上问题_multiset

    Code: // luogu-judger-enable-o2 #include<bits/stdc++.h> using namespace std; #define maxn 5000 ...

随机推荐

  1. 王垠:谈 Linux,Windows 和 Mac ( 2013)

    这段时间受到很多人的来信.他们看了我很早以前写的推崇 Linux 的文章,想知道如何“抛弃 Windows,学习 Linux”.天知道他们在哪里找到那么老的文章,真是好事不出门…… 我觉得我有责任消除 ...

  2. sql 添加自定义排序

    Mysql : SELECT (@i:=@i+1) AS ind ,字段 FROM 表名 别名, (SELECT @i:=0) t WHERE `IsDeleted` = 0; Oracle: 本就有 ...

  3. setImageEdgeInsets 和 setImage配合使用达到button区域大并可调节其上图片显示区域大小的效果

    [self.indicator setImage:[UIImage imageNamed:@"01_login_moreicon@2x.png"] forState:UIContr ...

  4. android 获得屏幕宽度和高度

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools= ...

  5. python内存诊断

    1.计算内存地址: str1 = 'shn' print id(str1) 2.计算内存大小,返回字节数 str1 = 'td' print sys.getsizeof(str1) 3.

  6. Solidworks如何绘制装饰螺纹线

    1 插入-注解,装饰螺纹线   2 绘制装饰螺纹线,选择螺纹的边线,标准选择ISO,下面可以选择的范围就确定了(M6的孔,只能选择M8的螺纹或者M10的螺纹),画好之后在3D图中并没有明确的螺纹样式 ...

  7. 【剑指offer】打印1到最大的n位数

    题目描写叙述: 输入数字n,按顺序打印出从1到最大的n位十进制数.比方输入3,则打印出1.2.3一直到最大的3位数即999. 分析描写叙述: 首先想到的是先计算出最大的n位数是多少,然后用一个循环从1 ...

  8. HDU 2825 Wireless Password (AC自己主动机,DP)

    pid=2825">http://acm.hdu.edu.cn/showproblem.php? pid=2825 Wireless Password Time Limit: 2000 ...

  9. string方法 PadLeft 返回一个新字符串,该字符串通过在此实例中的字符左侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符右对齐。 PadRight 右边

  10. struts(转)

    配置文件的优先级 在struts2中一些配置(比如常量)可以同时在struts-default.xml(只读性),strtus-plguin.xml(只读性),struts.xml,struts.pr ...