2018 German Collegiate Programming Contest (GCPC 18)(2020.5.5)
C、Coolest Ski Route
最长路跑一下。
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const ll INF = 1e10;
struct edge
{
ll to, value;
};
int main()
{
int n, m, s; cin >> n >> m;
vector <edge> G[n + 1];
vector <int> toward(n + 1, 0);
for (int i = 1; i <= m; ++i)
{
int a, b, c;
cin >> a >> b >> c;
G[a].push_back({b,c});
toward[b]++;
}
int ans = 0;
for (int i = 1; i <= n; ++i)
{
if (toward[i] == 0)
{
s = i;
priority_queue <P> que;
vector <ll> dis(n + 1, -1);
dis[s] = 0; que.push({0, s});
while (!que.empty())
{
P p = que.top(); que.pop();
int v = p.second, d = p.first;
if (d < dis[v]) continue;
for (int i = 0; i < G[v].size(); ++i)
{
edge e = G[v][i];
if (dis[e.to] < dis[v] + e.value)
{
dis[e.to] = dis[v] + e.value;
que.push({dis[e.to], e.to});
}
}
}
for (int i = 1; i <= n; ++i)
if (dis[i] != -1 && dis[i] > ans) ans = dis[i];
}
}
cout << ans << endl;
return 0;
}
D、Down the Pyramid
线段操作类问题,比较有意思。本身不难,这里先挂个代码,之后会在CF补题记录里面细讲。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 10;
int main()
{
int n; cin >> n;
static int a[MAXN];
for (int i = 1; i <= n; ++i) scanf("%d", a + i);
int sum = 0, l = 0, r = a[1];
for (int i = 1; i <= n; ++i)
{
if (i & 1) sum += a[i], r = min(r, sum);
else sum -= a[i], l = max(l, sum);
}
if (l > r) cout << 0 << endl;
else cout << r - l + 1 << endl;
return 0;
}
E、Expired License
一个普通的gcd,不过要注意精度问题。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool is_prime(int x)
{
if (x == 1) return 0;
for (int i = 2; i * i <= x; ++i)
if (x % i == 0) return 0;
return 1;
}
int main()
{
int n; cin >> n;
while (n--)
{
double a, b; cin >> a >> b;
int a_int = round(a * 1e5), b_int = round(b * 1e5);
int up = a_int / __gcd(a_int, b_int), down = b_int / __gcd(a_int, b_int);
if (up == down) cout << 2 << ' ' << 2 << endl;
else if (is_prime(up) && is_prime(down)) cout << up << ' ' << down << endl;
else cout << "impossible" << endl;
}
return 0;
}
F、Fighting Monsters
这题也是很有意思的一题。稍微写一下会发现这是个斐波那契。
考虑结束情况为 1 , 0 1,0 1,0。因此前一种情况一定是 1 , 0 + 1 = 1 1,0+1=1 1,0+1=1。其它的可能性就是不断相加,如 1 + 1 = 2 , 1 1+1=2,1 1+1=2,1; 2 , 1 + 2 = 3 2,1+2=3 2,1+2=3; 3 + 2 = 5 , 3 3+2=5,3 3+2=5,3…
然后列出来所有可能情况: 1 , 1 ; 2 , 1 ; 3 , 2 ; 5 , 3... 1,1;2,1;3,2;5,3... 1,1;2,1;3,2;5,3...
于是目标就是找出数列中相邻的斐波那契数。实现方面有一点小细节要注意。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
int main()
{
int n; cin >> n;
int a[MAXN] = {0}; map <int, int> mp;
vector <int> pos_1;
for (int i = 1; i <= n; ++i)
{
scanf("%d", a + i);
mp[a[i]] = i;
if (a[i] == 1) pos_1.push_back(i);
}
if (pos_1.size() >= 2)//"1,1"特判
{
cout << pos_1[0] << ' ' << pos_1[1] << endl;
return 0;
}
int fiba = 1, fibb = 2, temp;//发现除了"1,1"外其它的数对数字都不同,直接map处理一下就好了
while (fibb <= 1e6)//fiba < fibb
{
if (mp.count(fiba) && mp.count(fibb))
{
cout << mp[fiba] << ' ' << mp[fibb] << endl;
return 0;
}
temp = fiba + fibb;
fiba = fibb; fibb = temp;
}
cout << "impossible" << endl;
return 0;
}
H、Hyper Illuminati
就是求满足 Σ i = 1 s i n − 1 = m \Sigma_{i=1}^{s}i^{n-1}=m Σi=1sin−1=m的整数 s , n s,n s,n。枚举一下就好了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll qpow(ll a, ll b)
{
ll ans = 1;
while (b)
{
if (b & 1) ans *= a;
a *= a, b >>= 1;
}
return ans;
}
int main()
{
ll m; cin >> m;
for (int n = 3; n <= 64; ++n)
{
ll ans = 0, s = 0;
while (ans < m)
ans += qpow(++s, n - 1);
if (ans == m)
{
cout << n << ' ' << s << endl; return 0;
}
}
cout << "impossible" << endl;
return 0;
}
I、It’s Time for a Montage
这题读了我快二十分钟还云里雾里的。没啥意思,挂完代码就溜了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e3 + 10;
int main()
{
int n; cin >> n;
int h[MAXN], v[MAXN];
for (int i = 1; i <= n; ++i) scanf("%d", h + i);
for (int i = 1; i <= n; ++i) scanf("%d", v + i);
if (v[1] - h[1] < 0)
{
cout << 0 << endl;
return 0;
}
int ans = v[1] - h[1];
for (int i = 2; i <= n; ++i)
{
if (h[i] + ans > v[i]) break;
if (h[i] + ans < v[i])
{
ans++; break;
}
}
cout << ans << endl;
return 0;
}
L、Logic Puzzle
一个模拟。因为这题多给我们了最外面一圈,于是根据第一行而且并不需要一整行实际上就可以确定第一行的情况了。之后就是按照给的数据往下填,最后再回头计算一下填好的玩意儿的数值和原先的一不一样。
如果没给最外面一圈的话可以考虑枚举第一行状态。这样下面状态也是确定的。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXH = 110, MAXW = 110;
int main()
{
int h, w; cin >> h >> w;
h += 2, w += 2;
bool mp[MAXH][MAXW] = {0};
int dig[MAXH][MAXW] = {0}, sav[MAXH][MAXW] = {0};
for (int i = 1; i <= h; ++i)
for (int j = 1; j <= w; ++j)
{
scanf("%d", &dig[i][j]);
sav[i][j] = dig[i][j];
}
for (int i = 2; i <= h - 1; ++i)
for (int j = 2; j <= w - 1; ++j)
{
if (sav[i - 1][j - 1] == 1)
{
mp[i][j] = 1;
for (int dx = -1; dx <= 1; ++dx)
for (int dy = -1; dy <= 1; ++dy)
sav[i + dx][j + dy]--;
}
else if (sav[i - 1][j - 1] > 1 || sav[i - 1][j - 1] < 0)
{
cout << "impossible" << endl;
return 0;
}
}
for (int i = 1; i <= h; ++i)
for (int j = 1; j <= w; ++j)
{
int tot = 0;
for (int dx = -1; dx <= 1; ++dx)
for (int dy = -1; dy <= 1; ++dy)
if (mp[i + dx][j + dy]) ++tot;
if (tot != dig[i][j])
{
cout << "impossible" << endl;
return 0;
}
}
for (int i = 2; i <= h - 1; ++i)
{
for (int j = 2; j <= w - 1; ++j)
if (mp[i][j]) cout << 'X';
else cout << '.';
cout << endl;
}
return 0;
}