感官难度: C = D < A < E < B C=DC=D<A<E<B。
题意:给定一张无向图,图上边分为室外和室内两类,每条边有权值。求以室外的边权和为第一关键字,室内和室外的边权和为第二关键字的最短路。
直接用 pair 存一下这两个关键字即可。
#include
#define INF 10000000000000000ll
using namespace std;
typedef long long ll;
typedef pair<int, pair<ll, ll> > pill;
int n, m, p;
int to[80005], nxt[80005], tp[80005];
int w[80005], at[4005] = {0}, cnt = 0;
pair<ll, ll> dis[4005];
priority_queue<pill, vector<pill >, greater<pill > > pq;
int main(){
scanf("%d%d%d", &n, &m, &p);
char opt[3];
for (int i = 0, u, v, ww; i < m; ++i){
scanf("%d%d%d%s", &u, &v, &ww, opt);
int tpp = (opt[0] == 'I' ? 0: 1);
to[++cnt] = v, nxt[cnt] = at[u], w[cnt] = ww, tp[cnt] = tpp,
at[u] = cnt;
to[++cnt] = u, nxt[cnt] = at[v], w[cnt] = ww, tp[cnt] = tpp,
at[v] = cnt;
}
while (p--){
int u, v;
scanf("%d%d", &u, &v);
for (int i = 0; i < n; ++i)
dis[i].first = dis[i].second = INF;
dis[u].first = dis[u].second = 0;
pq.push(make_pair(u, dis[u]));
for (; ; ){
while (!pq.empty()){
if (pq.top().second > dis[pq.top().first])
pq.pop();
else break;
}
if (pq.empty()) break;
pill tmp = pq.top();
pq.pop();
int h = tmp.first;
ll dis_o = tmp.second.first, dis_tot = tmp.second.second;
for (int i = at[h]; i; i = nxt[i]){
if (tp[i]){
pair<ll, ll> tmp_dis(dis_o + w[i], dis_tot + w[i]);
if (tmp_dis < dis[to[i]]){
dis[to[i]] = tmp_dis;
pq.push(make_pair(to[i], tmp_dis));
}
}else {
pair<ll, ll> tmp_dis(dis_o, dis_tot + w[i]);
if (tmp_dis < dis[to[i]]){
dis[to[i]] = tmp_dis;
pq.push(make_pair(to[i], tmp_dis));
}
}
}
}
if (dis[v].first < INF) printf("%lld %lld\n", dis[v].first, dis[v].second);
else printf("IMPOSSIBLE\n");
}
return 0;
}
题意:给 6 条边,问能否组成一个体积非 0 的正四面体。多组数据。
枚举 6 条边的所有排列。首先保证能组成四个三角形,然后判断体积是否为 0。体积为 0 的情况只有一种:6 条边构成了平面图形。
这个不是很好判断。我的做法是固定一个底面,然后让其中一个侧面旋转到与底面共面,这时有两种情况:侧面与底面在公共边的两侧或者一侧。计算两种情况下侧面和底面各自非公共点之间的距离,记为 l 1 , l 2 l_1, l_2 l1,l2。
如果剩下的唯一没有用到的边长度在 l 1 , l 2 l_1, l_2 l1,l2 之间就表明可以形成。
#include
using namespace std;
typedef long long ll;
int n;
int l[10];
inline bool check(int x, int y, int z){
return (x + y > z) && (x + z > y) && (y + z > x);
}
inline ll sqr(ll x){
return x * x;
}
inline double sqr_d(double x){
return x * x;
}
int main(){
scanf("%d", &n);
while (n--){
for (int i = 0; i < 6; ++i)
scanf("%d", &l[i]);
sort(l, l + 6);
bool flag = false;
do{
if (!check(l[0], l[1], l[4]) || !check(l[3], l[4], l[5]) || !check(l[1], l[2], l[5])
|| !check(l[0], l[2], l[3])){
continue;
}
double cos_1 = (1.0 * sqr(l[3]) + 1.0 * sqr(l[5]) - 1.0 * sqr(l[4])) / (2.0 * l[3] * l[5]);
double sin_1 = sqrt(1 - cos_1 * cos_1); // bad in precision
double xx1 = l[3] * cos_1, yy1 = l[3] * sin_1;
double cos_2 = (1.0 * sqr(l[2]) + 1.0 * sqr(l[5]) - 1.0 * sqr(l[1])) / (2.0 * l[2] * l[5]);
double sin_2 = sqrt(1 - cos_2 * cos_2); // bad in precision
double xx2 = l[2] * cos_2, yy2 = l[2] * sin_2;
double dis1 = sqrt(sqr_d(xx1 - xx2) + sqr_d(yy1 - yy2));
double dis2 = sqrt(sqr_d(xx1 - xx2) + sqr_d(yy1 + yy2));
if ((l[0] - dis1) * (l[0] - dis2) < 0) {
flag = true;
break;
}
}while (next_permutation(l, l + 6));
if (flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}
题意:有一个未知的非负系数多项式 f f f,给定 f ( 1 ) , f ( f ( 1 ) ) f(1), f(f(1)) f(1),f(f(1)),问是否能算出 f f f 的各个系数,或者判别无解或者多解。
假设 f ( 1 ) = t f(1)=t f(1)=t。由于系数非负,我们可以立即特判几种情况:
然后就只有无解和唯一解的情况了。会发现此时 t ≥ 2 t\ge 2 t≥2,且各个系数均 ≤ t \le t ≤t。我们可以从低次项到高次项,迭代计算系数:
上述求解过程不保证最终的系数和为 t t t,因此最后要判定一下,不为 t t t 则无解。
#include
using namespace std;
int ans[1005], tot;
int main(){
int n;
scanf("%d", &n);
while (n--){
int a, b;
scanf("%d%d", &a, &b);
if (a < 0 || b < 0) {
printf("IMPOSSIBLE\n");
continue;
}
if (b < a){
printf("IMPOSSIBLE\n");
continue;
}
if (a == 0){
// f(x) = 0
if (b != 0) printf("IMPOSSIBLE\n");
else printf("0\n");
continue;
}
if (a == b){
// f(x) = x, or f(x) = c
if (a == 1) printf("AMBIGUOUS\n");
else printf("0\n");
continue;
}
if (a == 1){
// should be a = b
printf("IMPOSSIBLE\n");
continue;
}
// a >= 2
tot = 0;
int cur = 0;
for (; ; ){
if (b < a) {
ans[++tot] = b;
cur += b;
break;
}else if (b == a){
if (a - cur == 1){
ans[++tot] = 0;
ans[++tot] = 1;
++cur;
}else {
ans[++tot] = a;
cur += a;
}
break;
}else {
ans[++tot] = b % a;
cur += ans[tot];
b /= a;
}
}
if (cur != a){
printf("IMPOSSIBLE\n");
continue;
}
for (int i = tot; i >= 2; --i)
printf("%d ", ans[i]);
printf("%d\n", ans[1]);
}
return 0;
}
注意特判!注意特判!注意特判!
这场比赛的题目都不难,但是很容易掉进坑里,特别是 B 和 E!