【套题】qbxt国庆刷题班D2
D2
今天的题感觉还是好妙的
T1
Description
现在有一张\(n\)个节点\(m\)条边的无向连通图\(G=(V,E)\),满足这张图中不存在长度大于等于3的环且图中没有重边和自环。
定义两个点\(u,v\)的距离\(d(u,v)\)为这两个点之间最短路上的点数,求
\]
Input
第一行两个正整数n,m,表示点数边数
接下来\(m\)行,每行两个正整数,描述一条无向边
Output
一行一个整数代表答案。
Sample Input
7 6
1 2
1 6
2 5
3 1
4 7
2 4
Sample Output
3
Hint
\(For~All:\)
\(n,m~\leq~10^5\)
\(For~30~percent:\)
\(n,m~\leq~20\)
\(For~60~percent:\)
\(n,m~\leq~1000\)
Solution
考虑这个十分煞笔的描述……其实这是棵树
题意是让你找到一个点,使得这个点到最远的点的距离最小
考虑30分做法,直接Floyd即可
考虑60分做法……我不知道60分怎么做
考虑100做法。一个点像最远的点的路径只有可能有两种情况,分别是向上走和向下走的两种情况于是可以先一遍dfs确定一个点向下的最长路,然后树形DP求出这个点的最长路。具体的,对每个节点维护最长路和次长路,无需严格次长,同时维护分别是从哪里转移。显然根节点的最长路是向下的。对于一个非根节点,如果它的父亲的最长路是转移向他的,那么将它的最长路即为父亲的次长路,否则记为最长路。然后枚举这个节点的子节点,求出他向下的最长路,进行转移。至此这个节点的最长路与次长路已经被全部求出,然后可以枚举他的子节点向子节点转移。
hjc说这是个结论题。可我觉得这就是个树形DP吖?
Code
#include<cstdio>
#define rg register
#define ci const int
#define cl const long long int
namespace IO {
char buf[110];
}
template <typename T>
inline void qr(T &x) {
char ch=getchar(),lst=' ';
while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst == '-') x=-x;
}
template <typename T>
inline void write(T x,const char aft,const bool pt) {
if(x < 0) {putchar('-');x=-x;}
rg int top=0;
do {
IO::buf[++top]=x%10+'0';x/=10;
} while(x);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
}
template <typename T>
inline T mmax(const T a,const T b) {return a > b ? a : b;}
template <typename T>
inline T mmin(const T a,const T b) {return a < b ? a : b;}
template <typename T>
inline T mabs(const T x) {return x < 0 ? -x : x;}
template <typename T>
inline void mswap(T &a,T &b) {
T temp=a;a=b;b=temp;
}
const int maxn = 100010;
const int maxm = 200010;
struct Edge {
int to,nxt;
};
Edge edge[maxm];int hd[maxn],ecnt;
inline void cont(ci from,ci to) {
Edge &e=edge[++ecnt];
e.to=to;e.nxt=hd[from];hd[from]=ecnt;
}
int n,m,ans=0x3f3f3f3f;
int fa[maxn],frog[maxn][3],md[maxn],pre[maxn];
void DFS(ci);
void reading();
void dfs(ci,ci);
int main() {
freopen("distance.in","r",stdin);
freopen("distance.out","w",stdout);
qr(n);qr(m);
reading();
dfs(1,0);
DFS(1);
write(ans,'\n',true);
return 0;
}
void reading() {
rg int a,b;
while(m--) {
a=b=0;qr(a);qr(b);
cont(a,b);cont(b,a);
}
}
void dfs(ci u,ci fat) {
fa[u]=fat;
for(rg int i=hd[u];i;i=edge[i].nxt) {
int &to=edge[i].to;
if(to == fat) continue;
dfs(to,u);
md[u]=mmax(md[u],md[to]);
}
++md[u];
}
void DFS(ci u) {
if(pre[fa[u]] != u) frog[u][1]=frog[fa[u]][1]+1;
else frog[u][1]=frog[fa[u]][2]+1;
pre[u]=fa[u];
for(rg int i=hd[u];i;i=edge[i].nxt) {
int &to=edge[i].to;
if(to == fa[u]) continue;
if(frog[u][1] < (md[to]+1)) frog[u][2]=frog[u][1],frog[u][1]=md[to]+1,pre[u]=to;
else if(frog[u][2] < (md[to]+1)) frog[u][2]=md[to]+1;
}
for(rg int i=hd[u];i;i=edge[i].nxt) {
int &to=edge[i].to;
if(to == fa[u]) continue;
DFS(to);
}
ans=mmin(ans,frog[u][1]);
}
T2
Description
给你一张\(n\)个点\(m\)条边的无向图,每条边有一个权值\(w_i\)。
求一条\(S\)到\(T\)的路径,使得这条路上权值最大的边比权值最小的边比值最小
Input
第一行是两个正整数\(n,m\),代表图的点数和边数
接下来的\(m\)行每行三个正整数\(x,y,w\),代表一条权值为\(w\)的边
最后一行两个正整数\(S,T\)
Output
如果\(S\)到\(T\)不连通输出\(IMPOSSIBLE\),否则输出答案
答案形如一个A/B的既约分数
Hint
\(For~All:\)
\(1~\leq~n~\leq~500,1~\leq~m~\leq~5000,1~\leq~w~\leq~30000,x~\neq~y,S~\neq~T\)
\(For~20~percents:\)
\(n,m~\leq~5\)
\(For~other~30~percents:\)
\(n~\leq~100,m~\leq~200,w~\leq~100\)
Solution
考虑前20分可以暴力枚举选哪些边
剩下30分做法,考虑所有的元素都只有几百,于是可以使用bool型DP来做这道题。
可以设\(f_{i,j,k}=true/false\)代表从\(S\)到点\(i\),是否存在一个最大值为\(j\),最小值是\(k\)的路径。转移我不会。
我的做法是two points乱搞。考虑枚举最小的边,然后发现最小的边权单调不降时,最大的边权也单调不降。于是可以\(Two~points\)省掉最大边权的枚举。每次指针移动时暴力bfs判断连通性。于是复杂度\(O(m^2)\),其实就A了。然而我数组开小了,于是挂了50
考虑std的满分做法。发现边依然可以枚举。于是考虑枚举最小的边,发现问题等价于求一个最小瓶颈路。然后枚举最小边求暴力克鲁斯卡尔就可以AC。
Code
这代码写的可真丑
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = (int)1e4;
typedef int arr[N + 10];
int n, m, S, T;
arr ufs;
int bestnum, bestdenom;
struct edge {
int x, y, w;
}e[N + 10];
int find(int x) { return ufs[x] == x ? x : ufs[x] = find(ufs[x]); }
int gcd(int x, int y) { return y == 0 ? x : gcd(y, x % y); }
bool cmp(const edge &a, const edge &b) { return a.w < b.w; }
int main() {
freopen("graph.in", "r", stdin);
freopen("graph.out", "w", stdout);
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++i) scanf("%d %d %d", &e[i].x, &e[i].y, &e[i].w);
scanf("%d %d", &S, &T);
sort(e + 1, e + m + 1, cmp);
bestnum = 30001, bestdenom = 1;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) ufs[j] = j;
int j = i;
for ( ; j <= m; ++j) {
int fx = find(e[j].x), fy = find(e[j].y);
if (fx != fy) ufs[fx] = fy;
if (find(S) == find(T)) break;
}
if (find(S) == find(T)) {
if (e[j].w * bestdenom < e[i].w * bestnum)
bestnum = e[j].w, bestdenom = e[i].w;
}
}
if (bestnum == 30001) printf("IMPOSSIBLE\n");
else {
int g = gcd(bestnum, bestdenom);
bestnum /= g, bestdenom /= g;
if (bestdenom == 1) printf("%d\n", bestnum);
else printf("%d/%d\n", bestnum, bestdenom);
}
return 0;
}
T3
Description
有一个小学生去买糖,商店中共有n种不同的糖果,其中每一种糖果有两种选择:大糖果和小糖果各自只有一个,并且各自有一个价格。满足大糖果一定比小糖果贵。对于任意一种糖果,大糖果给小学生带来的愉悦度是2,小糖果给小学生带来的愉悦度是1。由于小学生不喜欢口味相同的糖果,所以对于一种糖果,他不会同时买大糖果和小糖果。
现在小朋友想要获得P点愉悦度,但花费最少的钱。请你帮帮他。
Input
第一行两个整数\(n,p\)
接下来\(n\)行,每行两个整数\(a_i\)和\(b_i\),表示第\(i\)种糖果小糖果和大糖果的价格。
Output
共输出\(n+1\)行。
第一行输出最小花费
对于\(i~\in~[2,n+1]\),第\(i\)行输出第\(i-1\)种糖果买大买小还是不买。不买输出\(0\),买小输出\(1\),买大输出\(2\)。如果有多种方案,那你就凉了。因为我不会写spj
Hint
\(For~All:\)
\(n~\leq~2~\times~10^5,a_i~\le~b_i,p~\leq~2~\times~n,b_i~\leq~2^21-1\)
\(For~30~percents:\)
\(n~\leq~10\)
\(For~other~20~percents:\)
\(n~\leq~1000,1~\leq~a_i~\leq~10~,~100~\leq~b_i~\leq~1000\)
Solution
显然可以DP。这样可以拿50分。
考虑贪心。
另外20分的做法。题目给定了\(a_i~\times~2~<~b_i\)
于是把两个糖果改为两个贡献都是\(1\)的,价格分别是\(a_i\)和\(b_i-a_i\),于是按照价格排序直接排序贪心。因为\(a_i\)显然小于\(b_i-a_i\),于是选了后者的时候一定选择了前者。贪心正确
考虑正解
于是就完了
【套题】qbxt国庆刷题班D2的更多相关文章
- 【套题】qbxt国庆刷题班D1
Day1 事实上D1的题目还是比较简单的= =然而D1T2爆炸了就十分尴尬--错失一波键盘 看题 T1 传送门 Description 现在你手里有一个计算器,上面显示了一个数\(S\),这个计算器十 ...
- JS、JAVA刷题和C刷题的一个很重要的区别
就是最近在做树方面的题时,发现JS和JAVA刷题和C刷题的一个很重要的区别就是传入null的区别 当遍历的时候,C传参数时可以传进去null的指针,因为递归进去,出来时,指针还是指着那个地方 但是JS ...
- 再也不用c刷题了!!——c++刷题必备
致读者: 博主是一名数据科学与大数据专业大二的学生,真正的一个互联网萌新,写博客一方面是为了记录自己的学习历程,一方面是希望能够帮助到很多和自己一样处于困惑的读者.由于水平有限,博客中难免会有一些错误 ...
- 2017北京国庆刷题Day5 afternoon
期望得分:100+60+100=260 实际得分:0+60+40=100 设图中有m个环,每个环有si条边,有k条边不在环中 ans= (2^s1 -2)*( 2^s2 -2)* (2^s3 -2)… ...
- 2017北京国庆刷题Day1 afternoon
期望得分:100+100+100=300 实际得分:100+100+100=300 T1 一道图论好题(graph) Time Limit:1000ms Memory Limit:128MB 题目 ...
- 2017北京国庆刷题Day7 morning
期望得分:100+0+100=200 实际得分:100+20+0=120 离散化搞搞 #include<cstdio> #include<iostream> #include& ...
- 2017北京国庆刷题Day3 morning
期望得分:100+60+0=160 实际得分:100+30+0=130 考场上用的哈希 #include<cstdio> #include<cstring> #include& ...
- 2017北京国庆刷题Day2 afternoon
期望得分:100+100+50=250 实际得分:100+70+50=220 T1 最大值(max) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一 ...
- 2017北京国庆刷题Day2 morning
期望得分:100+100+40=240 实际得分:100+40+0=140 T1 一道图论神题(god) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK ...
随机推荐
- 获取App的PackageName包名和LauncherActivity启动页
第一种情况: 查看手机里面已经安装的App: 用数据线连接手机, 打开开发者模式, 并赋予相关权限: 1. 清除日志: adb logcat -c 2. 启动日志: adb logcat Activi ...
- selenium自动化测试资源整理
1. 所有版本chrome下载 是不是很难找到老版本的chrome?博主收集了几个下载chrome老版本的网站,其中哪个下载的是原版的就不得而知了. http://www.slimjet.com/ch ...
- Vue 编程之路(二)——跳转页面传值
最近公司的一个项目中使用 Vue 2.0 + element UI 实现一个后台管理系统的前端部分,属于商城类型.其中我负责的部分有一项需要跳转页面,由于跳转前的页面是多个组件构成的,所以在跳转页面的 ...
- lintcode101 删除排序数组中的重复数字 II
删除排序数组中的重复数字 II 跟进“删除重复数字”: 如果可以允许出现两次重复将如何处理? 在:lintcode100删除排序数组中的重复数字 的基础上进行改进. class Solution ...
- SSH:远程登陆
SSH用于计算机之间的加密登录的前提是公钥为真,所以存在中间人攻击中间人攻击:与https协议不同,SSH协议的公钥是没有CA公证的,当对公钥的请求被中间截获时,中间人可以发出伪造公钥干坏事而不被识破 ...
- mysql中的select语句where条件group by ,having , order by,limit的顺序及用法
-- 语法: SELECT select_list FROM table_name [ WHERE search_condition ] [ GROUP BY group_by_expression ...
- HTML5 Geolocation位置信息定位总结
现在定位功能很常用,所以抽出一些时间将这个功能的知识总结一下作为知识梳理的依据.HTML5 Geolocation的定位用法很简单,首先请求位置信息,用户同意,则返回位置信息.HTML5 Geoloc ...
- C++标准库算法
一.只读算法 1. find() 2. count() 3. accumulate 4. equal 二.写入算法 1. fill 2. fill_n 3. copy 4. replace 5. re ...
- 初学c#(又要打代码了好难)
因为我原来从没有学过C#,所以要重新看一个语言的基本语法,仔细阅读了老师的作业要求,发现第一个10分的作业如果要用c语言写我是可以完成的,于是定个小目标就是在周日前完成作业的第一步.今天我在菜鸟教程的 ...
- HTTP 请求头 & 响应头
HTTP请求头概述 HTTP客户程序(例如浏览器),向服务器发送请求的时候必须指明请求类型(一般是GET或者POST).如有必要,客户程序还可以选择发送其他的请求头.大多数请求头并不是必需的, 但Co ...