• 题解-CF1380


    A Three Indices

    题意

    给你一个 (1-n) 的排列 (p),让你找到三个数 (i,j,k) 使得 $p_i < p_j $ 且 (p_j > p_k)

    解析

    先从前往后扫一遍,求出哪些位置满足存在一个比它小的在它前面。这可以用树状数组统计当前 (1-i) 中出现了几个。

    然后倒着在做一遍求出哪些位置存在一个比它小的在它后面。

    找到一个都满足的点,然后在它前面和后面都找一个比它小的即可。

    若不存在即为没有。

    #include <bits/stdc++.h>
    using namespace std;
    int t;
    int n;
    int a[1010];
    int c[1010];
    bool mark[1010], ans;
    int pos;
    int lowbit(int x){return x & -x;}
    void add(int x) {
    	while (x <= n) {
    		c[x]++;
    		x += lowbit(x);
    	}
    }
    int ask(int x) {
    	int ret = 0;
    	while (x) {
    		ret += c[x];
    		x -= lowbit(x);
    	}
    	return ret;
    }
    int main() {
    	cin >> t;
    	while (t--) {
    		ans = 0;
    		cin >> n;
    		for (int i = 1; i <= n; i++) c[i] = 0, mark[i] = 0;
    		for (int i = 1; i <= n; i++) cin >> a[i];
    		for (int i = 1; i <= n; i++) {
    			if (ask(a[i] - 1)) {
    				mark[i] = 1;
    			}
    			add(a[i]);
    		}
    		for (int i = 1; i <= n; i++) c[i] = 0;
    		for (int i = n; i; i--) {
    			if (mark[i] && ask(a[i] - 1)) {
    				pos = i;
    				ans = 1;
    				break;
    			}
    			add(a[i]);
    		}
    		if (ans) {
    			puts("YES");
    			for (int i = 1; i < pos; i++) {
    				if (a[i] < a[pos]) {
    					cout << i << " ";
    					break;
    				}
    			}
    			cout << pos << " ";
    			for (int i = pos + 1; i <= n; i++) {
    				if (a[i] < a[pos]) {
    					cout << i << endl;
    					break;
    				}
    			}
    		} else puts("NO");
    	}
    	return 0;
    }
    

    D Berserk And Fireball

    解析

    我们先在 (a) 中找到 (b),把这些位置标记下来,如果找不到则无解。

    然后对于每两个标记的数之间我们统计有多少个数((0)号位和(n+1)号位视为被标记的)。

    如果这个值小于 (k) 的话,我们只能 Berserk 把它们干掉,而如果这些数的最大值大于两端点标记的数的最大值则无解。所以我们还需记录这个最大值。

    如果这个值大于 (k) 的话则一定有解。

    分成两种情况:

    1、(y imes k < x)

    这种情况用 (k)Berserk 比用一次 Fireball 更优。

    但是最后不用 Fireball 可能干不掉全部的,所以我们要特判这种情况。

    如果最大值比两端点都要小,则不需要用 Fireball,一直用 Berserk 就行。

    否则我们一定要用一次 Fireball 把最大的干掉。剩下的全部用 Berserk

    2、(y imes k ge x)

    这种情况用 Fireball 更优,但是可能会出现剩余的情况,所以在用 Fireball 之前先用 Berserk 干到是 (k) 的倍数就行。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll N = 200010;
    ll n, m;
    ll x, y, k;
    ll a[N], b[N];
    ll top = 1;
    bool mark[N];
    ll ans, cnt, mx;
    int main() {
    	cin >> n >> m;
    	cin >> x >> k >> y;
    	for (ll i = 1; i <= n; i++) cin >> a[i];
    	for (ll i = 1; i <= m; i++) cin >> b[i];
    	for (ll i = 1; i <= n; i++) {
    		if (a[i] == b[top]) {
    			mark[i] = 1;
    			top++;
    		}
    	}
    	if (top < m) puts("-1");
    	else {
    		int lst = 0;
    		mark[n + 1] = 1;
    		for (int i = 1; i <= n + 1; i++) {
    			if (mark[i]) {
    				cnt = i - lst - 1;
    				if (cnt == 0) {
    					lst = i;
    					mx = 0;
    					continue;
    				}
    				if (cnt < k) {
    					if (mx < max(a[lst], a[i])) {
    						ans += y * cnt; 
    					} else {
    						puts("-1");
    						return 0;
    					}
    				} else {
    					if (y * k < x) {
    						if (mx < max(a[lst], a[i])) {
    							ans += y * cnt;
    						} else {
    							ans += y * (cnt - k) + x;
    						}
    					} else {
    						ans += cnt / k * x + (cnt % k) * y;
    					}
    				}
    				lst = i;
    				mx = 0;
    			} else {
    				mx = max(mx, a[i]);
    			}
    		}
    		cout << ans;
    	}
    	return 0;
    }
    
  • 相关阅读:
    设计模式之-装饰模式
    设计模式之-组合模式
    设计模式之-桥接模式
    设计模式之-适配器模式
    Java import static 静态导入
    C语言:字符数组 + 字符串指针
    leetcode 435.无重叠区间
    C++:强制类型转换
    C++:移动构造函数和移动赋值运算符
    编程:找出所有符合条件的元素
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14916091.html
Copyright © 2020-2023  润新知