2018, XI Samara Regional Intercollegiate Programming Contest
A. Restoring Numbers
题意:
给出两个数 a a a 和 b b b 的和 s s s 和最大公因数 g g g,要你求出任意一组 a a a 和 b b b 的解。
题解:
我们可以知道 g c d ( a , b ) = g gcd(a,b)=g gcd(a,b)=g,则我们假设 a = p ∗ g a=p*g a=p∗g, b = q ∗ g b=q*g b=q∗g,那么 s = ( p + q ) ∗ g s=(p+q)*g s=(p+q)∗g,由此可得有解的第一个条件是 s % g = 0 s\%g=0 s%g=0。
至于为什么是第一个,是因为题目描述 a a a 和 b b b 是正数,所以上设的 p p p 和 q q q 要大于 0 0 0,所以有解的第二个条件是 s / g > = 2 s/g>=2 s/g>=2,此时我们令 p = 1 p=1 p=1, q = s / g − 1 q=s/g-1 q=s/g−1,就得到了 p p p 和 q q q 的一组解,同时就得到了 a a a 和 b b b 的一组解。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
int s,g;scanf("%d%d",&s,&g);
if(s%g!=0||s/g==1) printf("-1\n");
else printf("%d %d\n",g,s-g);
return 0;
}
B. Minimal Area
题意:
按顺时针方向给出一个凸包上的所有点,问你以这个凸包上的点为顶点的非退化三角形的最小面积(的两倍,这个两倍应该是为了方便计算)。
题解:
考虑凸包的任意一条边作为底边,底边相同时高最小面积最小,而能做到高最小的顶点即为离底边最近的点,即从凸包上取相邻三点一定能找到最小的三角形,所以我们每次顺时针取三个点计算面积取最小值。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=200005;
struct vec{
ll x,y;
}p[maxn];
vec create(vec a,vec b){
return vec{
b.x-a.x,b.y-a.y};
}
ll area(vec a,vec b){
ll res=(a.x*b.y)-(b.x*a.y);
return res<0?-res:res;
}
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld%lld",&p[i].x,&p[i].y);
p[n+1]=p[1];p[n+2]=p[2];
ll ans=0x7fffffffffffffff;
for(int i=1;i<=n;i++){
vec a=create(p[i],p[i+1]);
vec b=create(p[i],p[i+2]);
ans=min(ans,area(a,b));
}
printf("%lld\n",ans);
return 0;
}
C. Third-Party Software
题意:
给出 n n n 条线段,问你最少选择多少个点,使得每条线段至少包含一个点,并给出这些点。
题解:
对线段进行排序,记录当前存放的节点,初始为 0 0 0。当遍历到的线段不包含当前点时,把这条线段的右端点放进答案,并更新当前点。这样首先能保证每条线段至少覆盖一个点,其次由于每次贪心选择右端点,保证选择的点尽可能少。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=200005;
struct node{
int l,r;
bool operator<(const node &t)const{
if(r!=t.r) return r<t.r;
else return l<t.l;
}
}p[maxn];
int ans[maxn],tot;
int main(){
int n;scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d%d",&p[i].l,&p[i].r);
sort(p,p+n);
int now=p[0].r;
ans[tot++]=now;
for(int i=1;i<n;i++){
if(p[i].l>now){
now=p[i].r;
ans[tot++]=now;
}
}
printf("%d\n",tot);
for(int i=0;i<tot;i++) printf("%d%c",ans[i],(i==tot-1)?'\n':' ');
return 0;
}
D. Transfer Window
题意:
总共有 n n n 类球员,你手里有 k k k 个种类为 a 1 a_1 a1, a 2 a_2 a2,…, a k a_k a