T1自由人
题目描述
在一个信奥训练营里,同学们都在努力的学习刷题,训练营规定了按照刷题速度和一次得分来衡量同学们的实力。假设同学甲和同学乙,如果甲的速度小于等于乙的速度,并且甲的得分大于等于乙的得分,则称乙同学就被甲同学所“影响”。当然,评分不会出现速度、得分都相同的情况。
显然,这个营里面总有一些同学是自由的,没有人能“影响”他们,请你找出这些自由的同学,按照速度从小到大输出。
输入输出格式
输入格式:
- 第一行n,表示n个同学
- 接下来n行,分别表示每个同学的速度和得分
- 数据确保不会出现速度和得分都相同
输出格式:
- 分多行输出自由的同学的速度和得分
- 按照速度从小到大,如果速度相同则按照得分从高到低
输入输出样例
输入样例1:
5
2 1
3 2
2 4
4 3
5 2
输出样例1:
2 4
测试点
测试点:5个测试点,每个测试点得20分。
测试限制:每个测试点时间限制1s,内存限制128M。
数据范围:
- 40%: 1<=n<=1000, 数据<=1000
- 100%:1<=n<=10^6, 数据<=10^9
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; struct Point { int x, y; bool operator < (const Point &p1) const { if(x == p1.x) return y > p1.y; return x < p1.x; } }; const int N=1e6+5; int n, last; Point a[N], ans[N]; void addAns(int idx) { ans[++last].x = a[idx].x; ans[last].y = a[idx].y; } int main() { scanf("%d", &n) ; for(int i=1; i<=n; i++) scanf("%d%d", &a[i].x, &a[i].y); sort(a+1, a+n+1); int mx = 0; for(int i=1; i<=n; i++) { if(a[i].y>a[mx].y) { addAns(i); mx = i; } } for(int i=1; i<=last; i++) printf("%d %d ", ans[i].x, ans[i].y); return 0; }
T2考试策略
题目描述
**高中的信息学竞赛训练队经过了刻苦的训练,现在终于进入考试策略制定环节了。
考试策略需要由老师和同学交流制定,老师和一个同学交流制定方案,然后该同学回去自己把方案明确成文档。每个老师一次只能和一个同学交流,交流完成后就可以再继续下一个,每个同学的交流时间和文档时间都有所不同。
为了提高效率,安排了两个老师陈老师和王老师,每个同学都可以自由选择和哪个老师交流,现在请你帮助计算一下,同学们该怎么安排(选老师和交流的顺序)才能使得所有人都完成文档撰写的时间点最小。
输入输出格式
输入格式:
- 第一行n,表示n个同学
- n行,每行2个数字,表示每个同学的交流时间ai和文档撰写时间bi
- 时间的单位都是分钟
输出格式:
- 一个数字,表示所有同学都完成文档撰写的时间点
输入输出样例
输入样例1:
5
2 2
9 6
5 9
6 4
3 4
输出样例1:
16
说明:
- 学生3、4、1按顺序选择陈老师,总完成时间点为14
- 学生2、5按顺序选择王老师,总完成时间带你为16
测试点
共10个测试点,每个10分。
测试限制:每个测试点时间限制1s,内存限制128。
数据范围:
- 样例1-2:n<=8,ai、bi<=50
- 样例3-4:n<=20,ai、bi<=200
- 样例5-10:n<=200, ai、bi<=500
- 样例5:ai都相等
- 样例6:bi都相等
void search(int k, int t1, int len1, int t2, int len2) //k表示现在第几个人了,t1是第一个老师花费的时间,以此
{ int mx = max(len1, len2);//保证每一位学生都整完自己撰写的稿子,取最大值 if(mx>=ans) return; if(k>n)
{ ans = min(ans, mx); return; } search(k+1, t1+p[k].a, max(t1+p[k].a+p[k].b, len1), t2, len2); search(k+1, t1, len1, t2+p[k].a, max(t2+p[k].a+p[k].b, len2)); } int main() { cin>>n; for(int i=1; i<=n; i++) cin>>p[i].a>>p[i].b; sort(p+1, p+n+1); search(1, 0, 0, 0, 0); cout<<ans<<endl; return 0; }
这就是核心的,然后就这么搜就行了,然而只能得40分
然后我们发现,每一个同学和老师交流的时间都是依附于上一位同学的交流完成的时间,所以我们发现,这就是DP呀
至于状态转移方程 f [ i ] [ j ]表示前i个同学总共花费了 j的时间,形成的最优解
然后 那么对于 第i个同学来说,他可以一号老师,也可以二号老师,完成这i的同学我们保证为最优解,也就是说,我们要求最小的时间,所以,去一号老师的时间
time1= max( f [i-1][j-a[i].talk] ,j+a[i].write); 也就 在上一个同学问完,或者这个同学在这个时间开始问
同理,time2=max( f[i-1][j],k+a[i].write );其中 k=前缀和 - 当前的时间节点
还有就是排序,从大到小排序
然后附上代码:
#include <iostream> #include <cstring> #include <cmath> #include <cstdio> #include <algorithm> #define inf 0x3f using namespace std; struct Node { int a, b; }; Node p[205]; int n, s[205],f[205][205*205], ans=inf; bool cmp(Node x,Node y) { return x.b>y.b; } int main() { cin>>n; for(int i=1; i<=n; i++) cin>>p[i].a>>p[i].b; sort(p+1, p+n+1,cmp); for(int i=1; i<=n; i++) s[i] = s[i-1]+p[i].a; for(int i=1; i<=n; i++) for(int j=0; j<=s[i]; j++) { int t1=inf, t2=inf; if(j>=p[i].a)//1号 t1 = max(f[i-1][j-p[i].a], j+p[i].b); int k = s[i]-j; if(k>=p[i].a)//2号 t2 = max(f[i-1][j], k+p[i].b);//2号 f[i][j] = min(t1, t2); } for(int j=0; j<=s[n]; j++) ans = min(ans, f[n][j]); cout<<ans<<endl; return 0; }
T3世界这么大
题目描述
奶牛们快乐的生活在草原上,它们的活动范围局限在各自一块独立的牛栏里,农场主为了方便管理修建了一些道路,使得每一块牛栏之间都可以通过道路到达。但由于经费有限,只修建了最少的道路,道路数为牛栏数减去1。
有一天,奶牛们突然开始了思考,它们很想知道,世界这么大,最远的同类到底在哪里呢?请你帮助它们找出,离每头奶牛最远的奶牛,它们的距离是多少?
输入输出格式
输入格式:
- 第一行输入n,表示奶牛(牛栏)数
- 接下来n-1行,表示连接一条道路,x、y为道路连接的两个牛栏,w为该道路的长度
输出格式:
- n个数,分别表示编号i的奶牛与离他最远的奶牛之间的距离
输入输出样例
输入样例1:
6
6 3 98
5 2 80
1 2 42
1 4 81
3 1 30
输出样例1:
128 170 152 209 250 250
样例1说明:
- 离奶牛1最远的是奶牛6,距离为30 + 98 = 128
- 离奶牛2最远的是奶牛6,距离为42 + 30 + 98 = 170
- ......
测试点
测试点:5个测试点,每个测试点得20分。
测试限制:每个测试点时间限制1s,内存限制128。
数据范围:
- 40%:1<=n<=10^3
- 100%:1<=n<=10^5
- 所有道路长度<=10^5
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int maxn=1e5; //vector<int> s[maxn]; int ans,n; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } struct node { int nxt,to,weath; }edge[maxn<<1]; int number_edge,head[maxn]; void add_edge(int from,int to,int wea) { number_edge++; edge[number_edge].nxt=head[from]; edge[number_edge].to=to; edge[number_edge].weath=wea; head[from]=number_edge; } void search(int x,int f,int len) { ans=max(ans,len); for(int i=head[x];i;i=edge[i].nxt) { if(edge[i].to==f) { continue; } search(edge[i].to,x,len+edge[i].weath); } } int main() { n=read(); for(int i=1;i<=n-1;i++) { int x=read(),y=read(),w=read(); add_edge(x,y,w); add_edge(y,x,w); } for(int i=1;i<=n;i++) { ans=0; search(i,0,0); cout<<ans<<" "; } return 0; }
得分 ==40分
然后就是正解,对于树上的任意一个点,到点x距离最远,那么x一定在树的直径上;
然后就只需要求解树的直径,并记录距离就OK了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int maxn=1e5; //vector<int> s[maxn]; int ans,n; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } struct node { int nxt,to,weath; }edge[maxn<<1]; int number_edge,head[maxn]; void add_edge(int from,int to,int wea) { number_edge++; edge[number_edge].nxt=head[from]; edge[number_edge].to=to; edge[number_edge].weath=wea; head[from]=number_edge; } int dis[maxn]; int pos,max_; void search(int x,int f,int len) { if(max_<len) { max_=len; pos=x; } for(int i=head[x];i;i=edge[i].nxt) { if(edge[i].to==f) { continue; } dis[edge[i].to]=max(dis[edge[i].to],len+edge[i].weath); search(edge[i].to,x,len+edge[i].weath); } } int main() { n=read(); for(int i=1;i<=n-1;i++) { int x=read(),y=read(),w=read(); add_edge(x,y,w); add_edge(y,x,w); } search(1,0,0); int p1=pos; search(p1,0,0); int p2=pos; search(p2,0,0); for(int i=1;i<=n;i++) { cout<<dis[i]<<" "; } return 0; }