A
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
reverse(s.begin(), s.end());
if(s[0] == 'n' && s[1] == 'a' && s[2] == 's') cout << "Yes";
else cout << "No";
return 0;
}
B
#include <bits/stdc++.h>
using namespace std;
int main() {
string a, b;
cin >> a >> b;
if(a == b) cout << 0;
else {
for(int i = 1; i <= max(a.length(), b.length()); i ++ ) {
if(a[i - 1] != b[i - 1]) {
cout << i;
break;
}
}
}
return 0;
}
C separated lunch
问题:
思路:注意到n很小,考虑爆搜
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n + 1);
int sum = 0;
for(int i = 1; i <= n; i ++ ) {
cin >> a[i];
sum += a[i];
}
int ans = 0x3f3f3f3f;
function<void(int, int)> dfs = [&](int start, int cnt) {
if(cnt >= sum - cnt) {
ans = min(ans, cnt);
return;
}
for(int i = start; i <= n; i ++ ) {
dfs(i + 1, a[i] + cnt);
}
};
dfs(1, 0);
cout << ans;
return 0;
}
D laser marking
问题:
思路:注意到n很小,因此考虑爆搜,对于所有的点,枚举出所有的连接顺序,这一点可以用next_permutation很快的实现(注意next permutation枚举的是字典序不大于当前序列的所有排列,因此想要枚举所有的情况,应在最开始对原有序列进行sort操作使得原有序列的字典序最小)
枚举出所有序列后再跑dfs枚举出这种序列下对于所有的线段哪一个端点优先连接
代码:
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
double find(double x) {
double l = 0, r = 10000000000;
while(l + eps <= r) {
double mid = (l + r) / 2;
if(mid * mid >= x) r = mid;
else l = mid;
}
return l;
}
int main() {
double n, s, t;
scanf("%lf%lf%lf", &n, &s, &t);
vector<pair<pair<double, double>, pair<double, double>>> pos(n + 1);
for(int i = 1; i <= n; i ++ ) {
double x, y;
double x1, y1;
scanf("%lf%lf%lf%lf", &x, &y, &x1, &y1);
pos[i] = {{x, y}, {x1, y1}};
}
sort(pos.begin() + 1, pos.end());
double ans = 1e9;
do {
//for(int i = 1; i <= n; i ++ )
double cnt = 1e9;
function<void(double, double, pair<double, double>)> dfs = [&](double u, double now, pair<double, double> last) {
if(u == n + 1) {
//cout << now << endl;
cnt = min(now, cnt);
return;
}
/*double b = find(((pos[u].first.first - last.first) * (pos[u].first.first - last.first) + (pos[u].second.second - last.second) * (pos[u].second.second - last.second))) / s;
b += find(((pos[u].first.first - pos[u].second.first) * (pos[u].first.first - pos[u].second.first) + (pos[u].first.second - pos[u].second.second) * (pos[u].first.second - pos[u].second.second))) / t;
dfs(u + 1, now + b, {pos[u].second.first, pos[u].second.second});
b = find((pos[u].second.first - last.first) * (pos[u].second.first - last.first) + (pos[u].first.second - last.second) * (pos[u].first.second - last.second)) / s;
b += find(((pos[u].first.first - pos[u].second.first) * (pos[u].first.first - pos[u].second.first) + (pos[u].first.second - pos[u].second.second) * (pos[u].first.second - pos[u].second.second))) / t;
dfs(u + 1, now + b, {pos[u].first.first, pos[u].first.second});*/
double b = find((pos[u].first.first - pos[u].second.first) * (pos[u].first.first - pos[u].second.first) + (pos[u].first.second - pos[u].second.second) * (pos[u].first.second - pos[u].second.second)) / t;
double c = find((pos[u].first.first - last.first) * (pos[u].first.first - last.first) + (pos[u].first.second - last.second) * (pos[u].first.second - last.second)) / s;
c += b;
dfs(u + 1, now + c, {pos[u].second.first, pos[u].second.second});
c = find((pos[u].second.first - last.first) * (pos[u].second.first - last.first) + (pos[u].second.second - last.second) * (pos[u].second.second - last.second)) / s;
c += b;
dfs(u + 1, now + c, {pos[u].first.first, pos[u].first.second});
};
dfs(1, 0, {0, 0});
ans = min(ans, cnt);
} while(next_permutation(pos.begin() + 1, pos.end()));
printf("%.6lf", ans);
return 0;
}
E
问题:
思路:求最小的最大值,显然二分,二分出答案之后,对于每个i,贪心地使得处理的机器大于二分的值,并且花费最小。对于每个i都有两种不同的选择,每个选择处理的数量 / 每个选择的价格 这个比值越大,就说明这种选择性价比越高,同时要注意到,选择性价比最好的机器不一定是最佳方案,因为可以有冗余,例如一个机器性价比很高,但价钱很贵,并且处理数量远远高出了我们的需求。这时注意到每种机器处理的数量都是不大于100的,这也就意味着性价比较差的那一台机器最多不会超过100台。例如高性价比机器a与其他机器b a可处理100个机器,b可处理1个机器,当有100台b时,是不如一台a更优的,因此可以枚举机器b的数量,时间复杂度
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ll n, x;
cin >> n >> x;
vector<pair<ll, ll>> a(n + 1), b(n + 1);
for(ll i = 1; i <= n; i ++ ) cin >> a[i].first >> a[i].second >> b[i].first >> b[i].second;//first数量second价格
auto check = [&](ll mid) {
ll now = 0;
for(ll i = 1; i <= n; i ++ ) {
ll num = a[i].first, cost = a[i].second;
ll num1 = b[i].first, cost1 = b[i].second;
if((double)b[i].first / b[i].second > (double)a[i].first / a[i].second) {
num = b[i].first;
cost = b[i].second;
num1 = a[i].first;
cost1 = a[i].second;
}//num cost是性价比高的机器
ll cnt = (mid + num - 1) / num * cost;
for(ll j = 0; j <= min(100ll, (mid + num1 - 1) / num1); j ++ ) {//枚举性价比低的机器要多少台
cnt = min(cnt, j * cost1 + (mid - (j * num1) + num - 1) / num * cost);
}
now += cnt;
}
return now <= x;
};
ll l = 0, r = 1000000000;
while(l < r) {
ll mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << l;
return 0;
}
F Shipping
问题:
思路:注意到n很小,时间t很大。如果不考虑时间的数据范围,这就是一道简单dp。设状态dp[i][j]表示从前i个时间段内选择,并且当前已经运送了j个物品第i个时间段我们可以由两个状态转移过来,即从i - x与i - 1转移,从i - 1转移表示第i个操作不用送任何物品,那么i - 1满足的状态i一定满足,因为不运送物品的天数增加了,对答案更加有利从i - x的转移就表示在这一天我要运输货物,那么从dp[i - x][j]就可以转移到dp[i][j ~ j + k]当然,如果dp[i - x][j]的数据非法的话,就直接跳过。这也是一种状态机dp。仔细观察后发现,如果我们贪心的去运输货物,那么运输货物的时间一定位于ti + z * x其中z是非负整数,并且题目中x,k均小于100,也就是说所有可能运输货物的时间不超过100 * 100个这样就实现了对时间离散化的处理
该题的时间复杂度为O(n ^ 3 * k) 数据范围100可以过
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 1e18;
int main() {
ll n, k, x;
cin >> n >> k >> x;
vector<ll> ti;
vector<ll> t(n + 1);
ti.push_back(-1e18);
for(int i = 1; i <= n; i ++ ) {
cin >> t[i];
for(int j = 0; j <= 100; j ++ ) {
ti.push_back(t[i] + j * x);
}
}
sort(ti.begin(), ti.end());
ti.erase(unique(ti.begin(), ti.end()), ti.end());
auto find = [&](ll x) {
int l = 0, r = ti.size() - 1;
while(l < r) {
int mid = l + r + 1 >> 1;
if(ti[mid] <= x) l = mid;
else r = mid - 1;
}
return l;
};
/*
dp[i][j] p[pre][]
*/
vector<vector<ll>> dp((n * 101 + 1), vector<ll>((n + 1), INF));
dp[0][0] = 0;
ll len = ti.size();
//cout << len;
for(int i = 1; i <= len - 1; i ++ ) {
ll pre = find(max(0ll, ti[i] - x));
//if(i == 1) cout << pre << " ";
//cout << pre << " ";
for(int j = 0; j <= n; j ++ ) {
dp[i][j] = min(dp[i][j], dp[i - 1][j]);
if(dp[pre][j] == INF) continue;
dp[i][j] = min(dp[i][j], dp[pre][j]);
ll cnt = 0;
for(int u = j + 1; u <= min(n, j + k); u ++ ) {
if(t[u] > ti[i]) break;
cnt += t[u];
dp[i][u] = min(dp[i][u], dp[pre][j] + ti[i] * (u - j) - cnt);
}
}
}
ll ans = INF;
for(int i = 1; i <= len - 1; i ++ ) ans = min(ans, dp[i][n]);
cout << ans;
return 0;
}