好像是2018年的宁夏邀请赛?
C. Caesar Cipher(字符串)
给出两个字符串,他们之间的关系是相同位置的字母之间有个位置移动的关系,根据给出的关系解码密文。
思路:直接计算给出的两个字符串之间的偏移关系,根据这个关系解码密文,注意对26取模,也要注意负数问题。
AC Code:
#include <bits/stdc++.h>
template <typename T>
inline void read(T &x) {
x = 0;
int f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - '0', ch = getchar();
}
x *= f;
}
template <typename T>
void write(T x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
#define INF 0x3f3f3f3f
typedef long long ll;
const double PI = acos(-1);
const double eps = 1e-6;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;
int t, n, m;
std::string s1, s2, s;
int main() {
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
std::ios::sync_with_stdio(false);
std::cin.tie(0);
while (std::cin >> t) {
for (int i = 1; i <= t; i++) {
std::cin >> n >> m;
std::cin >> s1 >> s2;
std::cin >> s;
int cnt;
cnt = s2[0] - 'A' - (s1[0] - 'A') ;
if (cnt < 0)
cnt += 26;
for (int j = 0; j < m; j++)
s[j] = (s[j] - 'A' - cnt + 26) % 26 + 'A';
std::cout << "Case #" << i << ": ";
std::cout << s << '\n';
}
}
return 0;
}
B. Rolling The Polygon(数学,几何)
一个多边形内有一个点,若令这个多边形每条边沿x轴转动,问这个点经过的轨迹长度。
思路: 连接该点与每个顶点,每次转动的轨迹都是绕某一顶点旋转成的扇形弧长。因为给出的顶点是按照顺序的,可以直接遍历,以每一个点为顶点,用余弦定理计算该点的内角大小,旋转的扇形角度就是外角大小,成点到顶点的距离就是扇形弧长,计算求和。怎样遍历第一个点和最后一个?令e[0]=e[n],e[n+1]=e[1]即可。
AC Code:
#include <bits/stdc++.h>
template <typename T>
inline void read(T &x) {
x = 0;
int f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - '0', ch = getchar();
}
x *= f;
}
template <typename T>
void write(T x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
#define INF 0x3f3f3f3f
typedef long long ll;
const double PI = acos(-1);
const double eps = 1e-6;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;
int t, n, a, b;
std::string s1, s2, s;
struct node {
double x, y;
} e[N];
double len(node x, node y) {
return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y));
}
double cal(node a, node b, node c, node d) {
double A = len(a, b);
double B = len(b, c);
double C = len(a, c);
double ang = (A * A + B * B - C * C) / (2 * A * B);
ang = PI - acos(ang);
return ang * len(b, d);
}
int main() {
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
while (std::cin >> t) {
for (int i = 1; i <= t; i++) {
std::cin >> n;
for (int j = 1; j <= n; j++) {
std::cin >> e[j].x >> e[j].y;
}
node ss;
std::cin >> ss.x >> ss.y;
e[0].x = e[n].x;
e[0].y = e[n].y;
e[n + 1].x = e[1].x;
e[n + 1].y = e[1].y;
double ans = 0;
for (int i = 1; i <= n; i++) {
ans += cal(e[i - 1], e[i], e[i + 1], ss);
}
std::cout << "Case #" << i << ": ";
printf("%.3lf\n", ans);
}
}
return 0;
}
os:想法大概是队友提出的,,,我只是个无情的敲代码机器hhhh
D. Take Your Seat(概率)
第一次坐飞机时,这个人是1号乘客但是他丢了机票,所以他上飞机后会随机选择一个座位坐下,而他后面上飞机的人若自己的座位被占了,那也会随机选择一个座位坐下,若自己的位置没被占,则会坐在自己的座位上,这一次上飞机是按照从1~n的顺序上的;
第二次坐飞机时,也有一个人丢了机票,人们上飞机后的行为与第一次一样,但是这次乘客上飞机的顺序是随机的;
问这两次最后一个上飞机的人可以坐在自己的位置上的概率。
思路: 第一种情况可以由数学归纳法得到结果:
n==1时,P(1)=1;
n==2时,第一个人上飞机随意选择一个座位,第二个人上飞机坐在自己位置上的概率P(2)=1/2;
n==3时,第一个人选择正确的座位概率P=1/3;若选择最后一个人的座位,则P=0;若选择第二个人的座位,那可以把第二个人选择位置转化成第一个人的情况,即P=1/3*1/2,综上所述,此时P(3)=1/3+0+1/3*P(2)=1/2;
n==4时,第一个人选择正确的位置P=1/4;若选择最后一个人的座位,则P=0;若选择第二个人的座位,则P=P(3)*1/4;若选择第三个人的位置,则P=P(2)*1/4;综上所述,此时P(4)=1/4+0+P(3)*1/4+P(2)*1/4=1/2;
根据数学归纳法,可以得到n等于任意值k时,概率均为1/2。
第二种情况可以这样考虑:
若丢了机票的人最后一个上飞机,那样每个人的座位都是正确的,则P=1/m,这个概率是丢了机票的人最后一个上飞机的概率;
若他是第i个上飞机的,则他之前的人座位均是正确的,从第i个人开始,上飞机的情况和概率与第一种情况相同,这样的上飞机顺序概率为1-1/m,则P=1/2*(1-1/m);
综上所述,P=1/m+1/2*(1-1/m)=(m+1)/(2*m)。
最后注意两种情况的特判,即人数为1时,P=1.
AC Code:
#include <bits/stdc++.h>
#pragma GCC optimize(2)
template <typename T>
inline void read(T &x) {
x = 0;
int f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - '0', ch = getchar();
}
x *= f;
}
template <typename T>
void write(T x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
#define INF 0x3f3f3f3f
typedef long long ll;
const double PI = acos(-1);
const double eps = 1e-6;
const int mod = 1e9 + 7;
const int N = 1e6 + 5;
int t;
double n, m;
int main() {
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
while (~scanf("%d", &t)) {
for (int k = 1; k <= t; k++) {
std::cin >> n >> m;
std::cout << "Case #" << k << ": ";
if (n == 1)
printf("1.000000 ");
else
printf("0.500000 ");
if (m == 1)
printf("1.000000\n");
else {
printf("%.6lf\n", (m + 1) / (2 * m));
}
}
}
return 0;
}
os:概率论还没有学过,但是概率计算的思想可以学习
H. Fight Against Monsters(结构体排序,贪心)
给出n个怪兽的生命值和攻击力,一开始怪兽先攻击,hero收到的伤害是所有未死亡怪兽的攻击力之和,hero每次只能打一个怪兽且对于每一个怪兽的攻击值是递增的,第一次打某个怪兽的伤害是1,第二次打同一个怪兽的伤害是2,以此类推,问hero在全部杀死怪兽前收到最少的伤害值是多少。
思路:结构体排序,但是注意排序方式。对于每只怪兽,先处理打击次数,我们应该先打平均伤害高的怪兽,即伤害/打击次数高的排在前面。不能只看伤害高这一参数,若某一怪兽伤害不高但是生命值很高也应该被考虑进去。
AC Code:
#include <bits/stdc++.h>
#pragma GCC optimize(2)
template <typename T>
inline void read(T &x) {
x = 0;
int f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - '0', ch = getchar();
}
x *= f;
}
template <typename T>
void write(T x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
#define INF 0x3f3f3f3f
typedef long long ll;
const double PI = acos(-1);
const double eps = 1e-6;
const int mod = 1e9 + 7;
const int N = 1e5 + 5;
int t, a[1005];
int n;
struct node {
int hp, att, tim;
} e[N];
void init() {
a[0] = 0;
for (int i = 1; i <= 1000; i++) {
a[i] = a[i - 1] + i;
}
}
bool cmp(node a, node b) {
if ((ll)a.att * (ll)b.tim > (ll)b.att * (ll)a.tim)
return true;
else
return false;
}
int main() {
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
std::ios::sync_with_stdio(false);
std::cin.tie(0);
init();
while (std::cin >> t) {
for (int k = 1; k <= t; k++) {
std::cin >> n;
for (int i = 1; i <= n; i++) {
std::cin >> e[i].hp >> e[i].att;
int pos = std::lower_bound(a + 1, a + 1 + 1000, e[i].hp) - a;
if (a[pos] < e[i].hp)
pos++;
e[i].tim = pos;
}
std::sort(e + 1, e + 1 + n, cmp);
ll ans = 0, sum = 0;
for (int i = 1; i <= n; i++) {
sum += e[i].att;
}
for (int i = 1; i <= n; i++) {
ans += (ll)e[i].tim * sum;
sum -= e[i].att;
}
std::cout << "Case #" << k << ": ";
std::cout << ans << '\n';
}
}
return 0;
}
A. Maximum Element In A Stack(模拟栈)
去原题摘了中间那一段代码,,,Gym里支离破碎的:
模拟堆栈,已经给出的rng61()函数直接复制即可,主函数就是给的gen(),我们需要模拟的就是满足gen()函数中的if,则将元素push进栈中,若不满足,则pop出栈,每次进入栈后,令最大值为栈顶,对于栈顶进行异或和乘法操作。
思路:复制原题目的代码,直接用数组模拟栈即可,注意每次进栈之后要比较与栈内数的大小关系,确定新的栈顶。
AC Code:
#include <bits/stdc++.h>
#pragma GCC optimize(2)
template <typename T>
inline void read(T &x) {
x = 0;
int f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - '0', ch = getchar();
}
x *= f;
}
template <typename T>
void write(T x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
#define INF 0x3f3f3f3f
typedef long long ll;
const double PI = acos(-1);
const double eps = 1e-6;
const int mod = 1e9 + 7;
const int N = 5e6 + 5;
int n, t, m, p, q;
unsigned int SA, SB, SC;
int cnt[N], cc[N];
ll s[N];
unsigned int rng61() {
SA ^= SA << 16;
SA ^= SA >> 5;
SA ^= SA << 1;
unsigned int t = SA;
SA = SB;
SB = SC;
SC ^= t ^ SA;
return SC;
}
int main() {
// freopen("test.in","r",stdin);
// freopen("output.in", "w", stdout);
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
for (int k = 1; k <= t; k++) {
std::cin >> n >> p >> q >> m >> SA >> SB >> SC;
ll ans = 0;
int top = 0;
for (int i = 1; i <= n; i++) {
if (rng61() % (p + q) < p) {
ll res = rng61() % m + 1;
s[++top] = res;
s[top] = std::max(s[top], s[top - 1]);
} else {
top = std::max(0, top - 1);
}
ans ^= ((ll)s[top] * (ll)i);
}
std::cout << "Case #" << k << ": ";
std::cout << ans << '\n';
}
return 0;
}
os:这个题非常不应该,,,俩人看了半天题没看懂,结果一看,嗐......
F. Moving On
每个城市都有一个被抢劫的概率,给出城市与城市之间距离的邻接矩阵,有q个询问,问从u到v所经过的城市的被抢劫概率都小于w的最短路。
思路: n的范围较小,我们可以用floyd,但是裸的floyd肯定TLE,所以需要对于这个被抢劫概率进行一个处理,需要对于每个点的点权进行排序,floyd对于每个w值不同的断点进行记录,这样预处理即可,就是O(N^3)的复杂度,可以通过。采用三维数组存从i到j经过最大w的位置为k的最短路径,需要数组的灵活运用。
AC Code:
#include <bits/stdc++.h>
template <typename T>
inline void read(T &x) {
x = 0;
int f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - '0', ch = getchar();
}
x *= f;
}
template <typename T>
void write(T x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
#define INF 0x3f3f3f3f
typedef long long ll;
const double PI = acos(-1);
const double eps = 1e-6;
const int mod = 1e9 + 7;
const int N = 200 + 5;
int i, j, k, n, m, t, q;
int f[N][N][N];
int r[N];
int id[N];
bool cmp(int a, int b) {
return r[a] < r[b];
}
int main() {
std::cin >> t;
for (int l = 1; l <= t; l++) {
std::cin >> n >> q;
for (i = 1; i <= n; i++) {
id[i] = i;
std::cin >> r[i];
}
std::sort(id + 1, id + 1 + n, cmp);
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
std::cin >> f[i][j][0];
}
}
for (k = 1; k <= n; k++) {
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
f[i][j][k] = std::min(f[i][j][k - 1], f[i][id[k]][k - 1] + f[id[k]][j][k - 1]);
}
}
}
printf("Case #%d:\n", l);
while (q--) {
int u, v, w;
std::cin >> u >> v >> w;
int ans = 0;
for (i = 1; i <= n; i++) {
if (r[id[i]] <= w)
ans = i;
}
std::cout << f[u][v][ans] << '\n';
}
}
return 0;
}
我也想继续补下面的题,,但是树状DP,状压什么的还没学,,,我滚了wwww
若有错误请指教orzorz