B. Alcoholic
我以为不会卡精度没有乘100,wa3次
C. Mandarin Orange
正解应该是单调栈,经典题目 最大矩形
但是 (n) 范围是 1e4
直接 (O(nlogn + n^2)) 用st表过了,跑了960ms / 1500ms
/*
* @Author: zhl
* @LastEditTime: 2021-01-23 20:19:20
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
int f[N][32];
int A[N];
int n, m, x, y;
void init() {
for (int i = 1; i <= n; i++) {
f[i][0] = A[i];
}
for (int j = 1; (1 << j) <= n; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
f[i][j] = min(f[i][j - 1], f[i + (1 << (j-1))][j - 1]);
}
}
}
int query(int l, int r) {
int k = log2(r - l + 1);
return min(f[l][k], f[r - (1 << k) + 1][k]);
}
int main(){
scanf("%d",&n);
for (int i = 1;i <= n;i++)scanf("%d", A + i);
init();
ll ans = 0;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= i;j++){
ans = max(ans, 1ll * query(j, i) * (i - j + 1));
}
}
printf("%lld
", ans);
}
D. Logical Expression
感觉肯定是个二进制,最低位填一个 1, 地位到高位从上往下
n = int(input())
ans, now = 1, 1
for _ in range(n):
s = input()
now = now * 2
if s == "OR":
ans += now
print(ans)
E. Rotate and Flip
题意
平面上有 (n) 个点,每次对所有的点操做,操作 (m) 次
有如下 4 种操作
1 : 所有点顺时针绕原点旋转 90°
2 : 所有点逆时针绕原点旋转 90°
3 p : 所有点关于 (x = p) 对称翻转
4 p : 所有点关于 (y = p) 对称翻转
有 (q) 次询问,每次询问第 (a_i) 个点在 (b_i) 次操作后的坐标
$ 1 le n,m,q le 2e5 $
(-10^9 le x_i,y_i,p_i le 10^9)
思路
设点坐标为 ((x,y))
1.顺时针: ((y,-x))
2.逆时针: ((-y,x))
3 : ((2p-x,y))
4 : ((x,2p-y))
发现只需要维护两边的符号和常数项,以及 (x,y) 是否交换了位置
int fx, fy, ax, ay, rev; // fx,fy 是符号, ax,ay 是常数项, rev表示 x,y 是否对换
void cal(int xx, int yy, int& resx, int& resy) {
if (rev)swap(xx, yy);
resx = xx * fx + ax;
resy = yy * fy + ay;
}
if (op[i] == 1) {
//(y,-x)
swap(fx, fy); swap(ax, ay); rev ^= 1, fy *= -1, ay *= -1;
}
else if (op[i] == 2) {
//(-y,x)
swap(fx, fy); swap(ax, ay); rev ^= 1, fx *= -1, ax *= -1;
}
else if (op[i] == 3) {
//(2p - x,y)
ax *= -1, fx *= -1;
ax += 2 * p[i];
}
else {
//(x, 2p - y)
ay *= -1, fy *= -1;
ay += 2 * p[i];
}
离线查询就可以,感觉有点麻烦,不知道别人怎么写的
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
int fx, fy, ax, ay, rev;
int n, m, q;
int x[N], y[N];
int ansx[N], ansy[N];
int op[N], p[N];
struct query {
int op, idx, id;
bool operator < (const query& b)const {
return op < b.op;
}
}Q[N];
void cal(int xx, int yy, int& resx, int& resy) {
if (rev)swap(xx, yy);
resx = xx * fx + ax;
resy = yy * fy + ay;
}
signed main() {
scanf("%lld", &n);
for (int i = 1; i <= n; i++) {
scanf("%lld%lld", x + i, y + i);
}
scanf("%lld", &m);
for (int i = 1; i <= m; i++) {
scanf("%lld", op + i);
if (op[i] > 2)scanf("%lld", p + i);
}
scanf("%lld", &q);
for (int i = 1; i <= q; i++) {
scanf("%lld%lld", &Q[i].op, &Q[i].idx);
Q[i].id = i;
}
sort(Q + 1, Q + 1 + q);
int idx = 1;
fx = fy = 1; ax = ay = 0; rev = 0;
while (idx <= q and Q[idx].op == 0) {
int pos = Q[idx].idx; int id = Q[idx].id;
if (rev == 1)cal(y[pos], x[pos], ansx[id], ansy[id]);
else cal(x[pos], y[pos], ansx[id], ansy[id]);
idx++;
}
for (int i = 1; i <= m; i++) {
if (op[i] == 1) {
//(
swap(fx, fy); swap(ax, ay); rev ^= 1, fy *= -1, ay *= -1;
}
else if (op[i] == 2) {
swap(fx, fy); swap(ax, ay); rev ^= 1, fx *= -1, ax *= -1;
}
else if (op[i] == 3) {
ax *= -1, fx *= -1;
ax += 2 * p[i];
}
else {
ay *= -1, fy *= -1;
ay += 2 * p[i];
}
while (idx <= q and Q[idx].op == i) {
int pos = Q[idx].idx; int id = Q[idx].id;
cal(x[pos], y[pos], ansx[id], ansy[id]);
idx++;
}
}
for (int i = 1; i <= q; i++) {
printf("%lld %lld
", ansx[i], ansy[i]);
}
}
F. Sugoroku2
题意
从 0 出发,每次投一次 (m) 个面的骰子(1-m) ,投出多少前进多少格,到达 n 或者经过 n 就算胜利。
有 k 个点,只要恰好到达这些点,就会被传送回起点,问胜利所需投骰子的期望次数,若无法取胜,则输出 -1
思路
设 f[i] 表示从 i 位置出发,胜利的期望步数
有 $f[i] = dfrac {sum_{j = 1}^ m f[i + j]} m + 1 $
于是可以从后往前推,若与原点连通,则 (f[i] = f[0]) , 可以设 (f[i] = a_icdot f[0] + b_i)
则 (f[i] = dfrac {sacdot f[0] + sb} m + 1) , sa, sb 表示 (sum_{j=i+1}^{i + m}) 的 (a_i) 与 (b_i) 的和
维护一个定长的和 sa,sb 就可以
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
int n, m, k;
int vis[N];
double a[N], b[N], sa, sb;
int main(){
scanf("%d%d%d", &n, &m, &k);
for(int i = 1;i <= k;i++){
int x;scanf("%d", &x);vis[x] = 1;
}
for(int i = n - 1;i >= 0;i--){
if (vis[i])a[i] = 1, b[i] = 0;
else{
a[i] = sa / m;b[i] = sb / m + 1;
}
sa += a[i] - a[i + m];
sb += b[i] - b[i + m];
}
if (fabs(a[0] - 1.0) < 1e-8)puts("-1");
else printf("%.8f
", b[0] / (1 - a[0]));
}