atcoder320
A
A - Leyland Number
题目概述:计算AB + BA
解题思路:由于数据范围较小,可以直接使用循环来做。但是我这里用的是pow()函数,但是需要注意的是pow()函数可能会有浮点数陷阱,所以尽可能要避免使用该函数。
点击查看代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>
#include <cmath>
using namespace std;
typedef long long LL;
typedef pair<int,int>PII;
map<string,int>ma;
const int N = 110;
int p[N];
int main(){
int a,b;
cin >> a >> b;
int res = pow(a,b) + pow(b,a);
cout << res << endl;
return 0;
}
B
B-Longest Palindrome
题目概述:给定以字符串,需要我们求出其最长连续回文子串。
解题思路:由于题目数据范围较小,直接暴力枚举其所有子串,并判断是否是回文串,再更新答案即可
点击查看代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
typedef pair<int,int>PII;
int main(){
string str;
cin >> str;
int n = str.size();
int maxlen = -1;
for(int i = 0; i < n; i ++)
for(int j = 0; i + j <= n; j ++){
string subs = str.substr(i,j);
//cout << subs << endl;
string src = subs;
reverse(subs.begin(),subs.end());
if(src == subs)maxlen = max(maxlen,(int)src.size());
}
cout << maxlen << endl;
return 0;
}
C
C - Slot Strategy 2 (Easy)
题目概述:有三个转盘(注意只有三个),每个转盘上有M个数字(0-9)。在0时刻,三个转盘都开始转动,在任意时刻你可以决定让其中一个转盘停下,问至少需要多长时间,你才能让三个转盘停下时显示的数字保持一致。
解题思路:由于数据范围较小,所以直接暴力枚举转盘停下时的每种情况。时间复杂度为\(O(N^3)\)
点击查看代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<int,int>PII;
const int INF = 1e9;
int main(){
int M;
cin >> M;
string str[3];
for(int i = 0; i < 3; i ++)cin >> str[i];
int res = INF;
//遍历每种情况
for(int i = 0; i < M; i ++){
for(int j = 0; j < M; j ++){
for(int p = 0; p < M; p ++){
if(str[0][i] != str[1][j] || str[0][i] != str[2][p])continue;
int t[3]{i,j,p};
//判断是否有相同的操作时间
if(t[0] == t[1])t[1] += M;
if(t[2] == t[0])t[2] += M;
if(t[2] == t[1])t[2] += M;
res = min(res,max({t[1],t[2],t[0]}));
}
}
}
if(res == INF)res = -1;
cout << res << endl;
return 0;
}
D
D - Relative Position
题目概述:给定1号点的坐标(0,0)以及M条信息(某两个点的相对坐标),问我们最终是否能够确定每个点的坐标,并输出。
解题思路:这种题型可以抽象为,用已知去推未知。可以使用dfs或bfs求解。我这里用的是bfs
点击查看代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<int,int>PII;
const int N = 200010,INF = 0x3f3f3f3f;
bool st[N];
LL x[N],y[N];
int n,m;
struct pos{
int b,c,d;
};
queue<int>q;
vector<pos>v[N];
int main(){
cin >> n >> m;
//cout << INF << endl;
memset(x,0x3f,sizeof x);
memset(y,0x3f,sizeof y);
st[1] = true;
x[1] = 0,y[1] = 0;
while(m --){
int a,b,c,d;
cin >> a >> b >> c >> d;
v[a].push_back({b,c,d});
v[b].push_back({a,-c,-d});
}
q.push(1);
while(q.size()){
int t = q.front();
q.pop();
for(auto ele : v[t]){
int b = ele.b,c = ele.c,d = ele.d;
if(!st[b]){
st[b] = true;
q.push(b);
x[b] = (LL)x[t] + c,y[b] = (LL)y[t] + d;
}
}
}
for(int i = 1; i <= n; i ++){
if(x[i] > 3 * 1e14 || y[i] > 3 * 1e14)puts("undecidable");
else cout << x[i] << " " << y[i] << endl;
}
return 0;
}
E
E - Somen Nagashi
题目概述:有n个人排队吃面,在T_i时刻会有W_i的面流下,排在前面的人可以得到该数量的面,并离开队列,在s_i后将会返回队列,并且是原来的位置。问当所有事件结束后,每个人得到的面条的数量。
解题思路:这种题型可以归为事件类题型,我们可以抽象出两个基本事件。1.就是题目中的面条流下事件;2. 得到面条的人离开队列以及在s_i后回归队列。可以使用STL中set来维护这两个事件。
点击查看代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <queue>
//#define x first
//#define y second
using namespace std;
typedef long long LL;
typedef pair<LL,LL>PLL;
const int N = 200010;
struct Event{
int t,w,s;
bool operator<(const Event &b)const{
if(this->t != b.t)return this->t < b.t;
else if(this->w != b.w)return this->w < b.w;
return this->s < b.s;
}
};
LL res[N];
set<int>q;
set<Event>event;
int main(){
int n,m;
cin >> n >> m;
for(int i = 1; i <= n; i ++){
q.insert(i);
}
while(m --){
int t,s,w;
cin >> t >> w >> s;
event.insert({t,w,s});
}
while(event.size()){
auto x = *event.begin();
event.erase(x);
//判断是那种事件
if(x.w < 0)q.insert(-x.w);
else{
//队列中没有人
if(!q.size())continue;
else{
//通过迭代器取值
auto t = *q.begin();
//从队列中删去
q.erase(t);
res[t] = (LL)res[t] + x.w;
//增加一个事件,由于回归队列事件需排在面留下事件后,我们使其为负数
event.insert({x.t + x.s,-t,0});
}
}
}
for(int i = 1; i <= n; i ++)cout << res[i] << endl;
return 0;
}
F
F - Fuel Round Trip
题目概述:驾驶一辆储油量为H的汽车从起点到终点往返一次,每两点之间的距离就是耗油量,只能从一个点到其相邻点。途中有n-1个加油站,问最少需要多少钱才能往返一次,如果不行输出-1.
解题思路:同时考虑去程和回程的dp
点击查看代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX_SIZE = 301;
// dp[pos][v1][v2] 代表只考虑 X_1 ~ X_pos,
// 去程至 X_pos 时恰有 v1 的油,回程至 X_pos 至多有 v2 的油至少要花多少钱
int dp[MAX_SIZE][MAX_SIZE][MAX_SIZE];
void update(int &x, int v) {
if(x == -1 || x > v) {
x = v;
}
}
int main() {
int N, H, X[MAX_SIZE], P[MAX_SIZE], F[MAX_SIZE];
cin >> N >> H;
X[0] = 0;
for(int i = 1; i <= N; i++) {
cin >> X[i];
}
for(int i = 1; i < N; i++) {
cin >> P[i] >> F[i];
}
memset(dp, -1, sizeof(dp));
dp[0][H][0] = 0;
for(int pos = 0; pos < N - 1; pos++) {
int dis = X[pos + 1] - X[pos];
for(int v1 = 0; v1 <= H; v1++) {
for(int v2 = 0; v2 <= H; v2++) {
if(dp[pos][v1][v2] == -1) continue;
if(v2 + 1 <= H) {
update(dp[pos][v1][v2 + 1], dp[pos][v1][v2]);
}
//判断能否到达下一点
if(v1 >= dis && v2 + dis <= H) {
// 在位置 pos + 1 不加油
update(dp[pos + 1][v1 - dis][v2 + dis], dp[pos][v1][v2]);
// 位置 pos + 1 给去程加油
update(dp[pos + 1][min(v1 - dis + F[pos + 1], H)][v2 + dis], dp[pos][v1][v2] + P[pos + 1]);
// 位置 pos + 1 给回程加油
if(v2 + dis >= F[pos + 1]) {
update(dp[pos + 1][v1 - dis][v2 + dis - F[pos + 1]], dp[pos][v1][v2] + P[pos + 1]);
}
}
}
}
}
int last_dis = (X[N] - X[N - 1]) * 2;
int answer = -1;
for(int v1 = 0; v1 <= H; v1++) {
for(int v2 = 0; v2 <= H; v2++) {
if(dp[N - 1][v1][v2] == -1) continue;
if(v1 - last_dis >= v2) {
update(answer, dp[N - 1][v1][v2]);
}
}
}
cout << answer << '\n';
}
浙公网安备 33010602011771号