A. Word Correction
题目大意
设 a,e,i,o,u,y a , e , i , o , u , y 是六个特殊字母,如果一个小写字母串从左往右读,出现连续两个特殊字母时,则删除后面这个特殊字母,直至没有连续两个特殊字母,输出这样处理后的字符串。
思路 - 模拟
按照题意模拟即可:
i
i
表示将要输出的字母,表示下一个可能会输出的字母
①如果
i,j
i
,
j
都是特殊字母,则
i
i
不变,令变为下一个字母
②如果
i,j
i
,
j
至少有一个不是特殊字母,则输出
i
i
,然后令,
j
j
变为下一个字母
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 103;
int n;
char s[MAXN];
inline bool isVowel(char ch) {
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' || ch == 'y';
}
int main() {
while(2 == scanf("%d%s", &n, s)) {
for(int i = 0, j = 1; i < n;) {
if(isVowel(s[i]) && isVowel(s[j])) {
++j;
}
else {
printf("%c", s[i]);
i = j;
if(j < n) {
++j;
}
}
}
printf("\n");
}
}
B. Run For Your Prize
题目大意
在一条数轴上坐标为范围内有 n n 个奖品,甲可以从坐标为的位置开始拿奖品,乙可以从坐标为 106 10 6 的位置开始拿奖品,两人每移动一个单位距离需要 1 1 秒,拿奖品不耗时,求两人把所有奖品拿完的最短耗时?
思路 - 模拟
枚举相邻的两个奖品(左边分别为),甲拿前者及其左边的奖品,乙拿后者及其右边的奖品,则总耗时为 max(i−1,106−j) m a x ( i − 1 , 10 6 − j ) ,取最小值。注意边界值,及甲或者乙不拿奖品的时候。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int END = 1e6;
int n;
int last, cur, ans;
int main() {
while(1 == scanf("%d", &n)) {
ans = END;
last = 0;
while(n-- > 0) {
scanf("%d", &cur);
ans = min(ans, max(END - cur, last - 1));
last = cur;
}
ans = min(ans, last - 1);
printf("%d\n", ans);
}
}
C. Constructing Tests
题目大意
设一个 n n 阶方阵,若其每一个 m m 阶子方阵内都至少含有一个,此时这个 n n 阶方阵内最多能有个 1 1 。现在给定,构造 n,m n , m 使其满足上述条件,无法构造则输出 −1 − 1 。
思路 - 枚举
用将
n
n
阶方阵划分成不重叠的阶方阵,不够的不计算,则共能划分成
⌊nm⌋2
⌊
n
m
⌋
2
个完整的
m
m
阶方阵,每个方阵右下角取,其全为
1
1
,则能满足题意。从而得到关系:。
又:
m=1
m
=
1
时,
k
k
横为,且
n
n
不变时,随着
m
m
的递增而非递减,可知对于每一个,
k
k
的下界为,从而由
k
k
得到的上界为
4k3−−√
4
k
3
,所以枚举
n
n
,然后计算得,再判断
n,m,k
n
,
m
,
k
是否满足得到的关系即可。
代码
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const double EPS = 1e-6;
int x;
int main() {
int T;
scanf("%d", &T);
while(T-- > 0) {
scanf("%d", &x);
if(x == 0) {
printf("1 1\n");
continue;
}
bool flag = false;
for(int n = 2; ((3LL * n * n) >> 2LL) <= x; ++n) {
long long tmp = 1LL * n * n - x;
if(tmp > 0) {
int n_m = sqrt(tmp) + EPS;
int m = n / n_m;
if(n * n - (n / m) * (n / m) == x) {
printf("%d %d\n", n, m);
flag = true;
break;
}
}
}
if(!flag) {
printf("-1\n");
}
}
}
D. Buy a Ticket
题目大意
给定一个 n n 个顶点,条边的无向图,每条边都有权值 w w ,每个顶点有权值,对于每一个顶点 i i 找出一个顶点( i i 到的最短路径为 dist d i s t , j j 的权值为),使得: 2dist+x 2 d i s t + x 最小。
思路 - Dijkstra
设置一个超级源点,其到每个顶点都有条无向边,权值为该顶点的权值,则问题转化为单元最短路,直接用堆优化的 Dijkstra D i j k s t r a 即可。
代码
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN = 200003;
const int MAXM = 200003;
struct Node {
int v;
long long w;
Node() {}
Node(int v, long long w):v(v), w(w) {}
bool operator< (const Node& a) const {
return w > a.w;
}
};
struct Edge {
int v, nxt;
long long w;
}edge[(MAXM + MAXN) << 1];
int tot, fir[MAXN];
void init() {
tot = 0;
memset(fir, -1, sizeof(fir));
}
void addEdge(int u, int v, long long w) {
edge[tot].v = v;
edge[tot].w = w;
edge[tot].nxt = fir[u];
fir[u] = tot++;
edge[tot].v = u;
edge[tot].w = w;
edge[tot].nxt = fir[v];
fir[v] = tot++;
}
int n, m;
long long a;
long long dist[MAXN];
bool vis[MAXN];
void dijkstra() {
memset(vis, false, sizeof(vis));
memset(dist, 0x3f, sizeof(dist));
dist[0] = 0;
priority_queue<Node> q;
q.push(Node(0, dist[0]));
int u, v;
long long w;
Node cur;
while(!q.empty()) {
cur = q.top();
u = cur.v;
w = cur.w;
q.pop();
if(vis[u]) {
continue;
}
vis[u] = true;
for(int i = fir[u]; i != -1; i = edge[i].nxt) {
v = edge[i].v;
w = edge[i].w;
if(dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
q.push(Node(v, dist[v]));
}
}
}
}
int main() {
int u, v;
long long w;
while(2 == scanf("%d%d", &n, &m)) {
init();
while(m-- > 0) {
scanf("%d%d%I64d", &u, &v, &w);
addEdge(u, v, w << 1LL);
}
for(int i = 1; i <= n; ++i) {
scanf("%I64d", &a);
addEdge(0, i, a);
}
dijkstra();
for(int i = 1;i <= n; ++i) {
printf("%I64d%c", dist[i], i == n ? '\n' : ' ');
}
}
}