Loading

ABC189

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\n", 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\n", 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_i\cdot f[0] + b_i\)

\(f[i] = \dfrac {sa\cdot 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\n", b[0] / (1 - a[0]));
}
posted @ 2021-01-23 21:51  —O0oO-  阅读(194)  评论(2编辑  收藏  举报