AtCoder Beginner Contest 192
D - Base n
题意: 给出n,m,设n中最大的数字为x,问在不同的进制(bas>x)下,小于等于m的不同的数有多少个
题解: 二分。 发现进制其实有单调性,进制越大,得到的值越大。那么我直接二分。然后需要特判下一位的情况。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int LL
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
int const MAXN = 2e5 + 10;
int n, T;
string s;
LL m;
LL tmp[MAXN];
LL ss[MAXN];
bool check(LL mid) {
LL mm = m;
int cnt = 0;
while (mm) {
tmp[cnt++] = mm % mid;
mm /= mid;
if (cnt > 70) break;
}
if (cnt > s.size())
return 1;
else if (cnt < s.size())
return 0;
else {
for (int i = cnt - 1; i >= 0; i--) {
if (tmp[i] > ss[i]) return 1;
if (tmp[i] < ss[i]) return 0;
}
}
return 1;
}
signed main() {
cin >> s;
for (int i = 0; i < s.size(); i++) {
ss[(int)s.size() - i - 1] = s[i] - '0';
}
cin >> m;
LL maxn = 0;
for (int i = 0; i < s.size(); i++) {
maxn = max(maxn, (LL)(s[i] - '0'));
}
if (s.size() == 1) {
if (s[0] - '0' <= m)
cout << 1;
else
cout << 0;
return 0;
}
/*
if (check(maxn + 1) == false)
{
cout << 0;
return 0;
}
*/
LL l = maxn , r = 1e18;
while (l < r) {
LL mid = (l + r + 1) >> 1; // 区别:有无加1
if (check(mid))
l = mid; //区别
else
r = mid - 1; //区别
}
cout << l - maxn << endl;
return 0;
}
E - Train
题意: 有n座城市之间有m条双向高铁线路连接,第i条高铁线路会在ki的倍数的时刻进站(包括0倍),花费ti的时间到另一个端点,问S到T的最短时间。 1 < = N < = 1 e 5 1<=N<=1e5 1<=N<=1e5
题解: 最短路变形。一辆人如果到达u点,然而这时高铁没有发车,那么这个人必然等到一发车就走,因此只需要找到大于等于u点时刻的最早发车时刻,以这个时刻来作为u点最短路来更新邻边。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
typedef pair<int, int> PII;
int const N = 4e5 + 10;
int e[N], ne[N], w[N], h[N], idx, n, m, dis[N], st[N], x, y, s[N];
void add(int a, int b, int c, int d) {
e[idx] = b, w[idx] = c, s[idx] = d, ne[idx] = h[a], h[a] = idx++;
}
// 堆优化版dijksyta
int dijkstra() {
memset(dis, 0x3f, sizeof dis); // 初始化距离为无穷
priority_queue<PII, vector<PII>, greater<PII> > q; // 定义一个按照距离从小到大排序的优先队列,第一维:距离,第二维:点
dis[x] = 0; // 一开始源点距离为0
q.push({0, x}); // 把源点信息放入队列
while (q.size()) { // 每个点只出入队列一次
auto t = q.top();
q.pop();
int distance = t.first, ver = t.second; // 最小距离和相对应的点
if (st[ver]) continue; // 这个操作保证每个点只出入队一次,因为队列里面可能会出现{dis1[3], 3}, {dis2[3], 3}的情况,这样保证dis1[3]<dis2[3]时,3号点只进出入队一次
st[ver] = 1; // 标记,因为dijkstra的贪心策略保证每个点只需要进出队一次
for (int i = h[ver]; ~i; i = ne[i]) { // 遍历ver的邻接点
int j = e[i];
// d[e[i]]=(d[u]+s[i]-1)/s[i]*s[i]+w[i];
if (dis[j] > w[i] + (int)ceil((double)distance / s[i]) * s[i]) {
dis[j] = w[i] + (int)ceil((double)distance / s[i]) * s[i];
q.push({dis[j], j}); // 这里不需要判断st,因为一旦更新发现更小必须放入队列
}
}
}
return dis[y] != 0x3f3f3f3f3f3f3f3f? dis[y]: -1;
}
signed main() {
n = read(), m = read(), x = read(), y = read();
memset(h, -1, sizeof h);
for (int i = 1, a, b, c, d; i <= m; ++i) { // 读入m条边
a = read(), b = read(), c = read(), d = read();
add(a, b, c, d), add(b, a, c, d);
}
if (x == y) {
cout <<0 << endl;
return 0;
}
cout << dijkstra();
return 0;
}
F - Potion
题意: 有n个数,你可以在第0个时刻条任意多个数出来,并让计数器加上他们的和,设你挑了k个数,那么之后每个时刻计数器都会加k,你要最小化计数器恰好到x的时间。 1 < = n < = 100 , 1 < = a i < = 1 e 7 , 1 0 9 < = X < = 1 0 1 8 1<=n<=100,1<=a_i<=1e7,10^9<=X<=10^18 1<=n<=100,1<=ai<=1e7,109<=X<=1018
题解: 01背包变形。看到x其实很小,那么直接枚举x,然后不断更新答案。设挑了s个数出来,那么为了满足题意,他们的和对s取余一定等于x%s。
那么考虑dp,f(i,j,k)表示前i个数挑了j个数出来,对s取余结果为k,枚举第i个数是否取即可。具体看:https://www.cnblogs.com/szmssf/p/14423803.html
代码: 贴上大佬代码
#include <bits/stdc++.h>
#define N 105
#define int long long
using namespace std;
int n, f[N][N][N], a[N], X, ans = 1e18;
signed main() {
cin >> n >> X;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int S = 1; S <= n; S++) {
memset(f, -0x3f, sizeof(f));
f[0][0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= S; j++) {
for (int k = 0; k <= n; k++) {
f[i][j][k] = max(f[i - 1][j][k], f[i - 1][j - 1][((k - a[i]) % S + S) % S] + a[i]);
}
}
}
if (f[n][S][X % S] < 0)
continue;
else
ans = min(ans, (X - f[n][S][X % S]) / S);
}
printf("%lld\n", ans);
return 0;
}