1853 Round 887 (Div. 2)

Desorting

定义一次操作为选定一个 i ,令 a1i 自增, ai+1n ,自减,求使得整个序列无序的最小操作次数

若序列一开始就无序,输出 0

否则找到相邻两数差值最小的位置,在这个位置不断使用操作,可以证明这是最优方案

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 5e2 + 7;
 
int a[N];
 
int T, n;
 
inline bool check() {
	for (int i = 2; i <= n; ++i)
		if (a[i] < a[i - 1])
			return true;
	
	return false;
}
 
signed main() {
	scanf("%d", &T);
	
	for (; T; --T) {
		scanf("%d", &n);
		
		for (int i = 1; i <= n; ++i)
			scanf("%d", a + i);
		
		if (check()) {
			puts("0");
			continue;
		}
		
		int minn = inf;
		
		for (int i = 2; i <= n; ++i)
			minn = min(minn, a[i] - a[i - 1]);
		
		printf("%d\n", minn / 2 + 1);
	}
	return 0;
}

Fibonaccharsis

给定斐波那契数列的第 kn ,求 f1,f2 有多少种可能性

注意到斐波那契数列的增长速度十分快,且知道相邻两项之后就能快速推出 f1,f2 ,考虑枚举第 k1 项,暴力递推到 f1,f2 即可

时间复杂度 O(nlogn)

#include <bits/stdc++.h>
using namespace std;

int T, n, K;

inline bool check(int f1, int f2, int pos) {
	int f0;
	
	while (pos--) {
		f0 = f2 - f1;
		
		if (f0 < 0)
			return false;
		
		f2 = f1, f1 = f0;
	}
	
	return f1 <= f2;
}

signed main() {
	scanf("%d", &T);
	
	for (; T; --T) {
		scanf("%d%d", &n, &K);
		int ans = 0;
		
		for (int i = 1; i <= n; ++i)
			ans += check(i, n, K - 2);
		
		printf("%d\n", ans);
	}
	
	return 0;
}

Ntarsis' Set

对于一个无限长的序列 1,2,3, ,每次删除前 a1,a2,,an 小的数字, k 次操作后求序列最小值

注意到对于任何一个数,只有删除比它小的数才会使得它更进一步被删掉,二分答案判断是否会被删掉即可

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 2e5 + 7;

int a[N];

int T, n, K;

inline bool check(int k, ll mid) {
	while (k--)
		mid -= upper_bound(a + 1, a + 1 + n, mid) - a - 1;
	
	return mid < 1;
}

signed main() {
	scanf("%d", &T);
	
	for (; T; --T) {
		scanf("%d%d", &n, &K);
		
		for (int i = 1; i <= n; ++i)
			scanf("%d", a + i);
		
		ll l = 1, r = 1e12, ans = 1;
		
		while (l <= r) {
			ll mid = (l + r) >> 1;
			
			if (check(K, mid))
				l = mid + 1;
			else
				ans = mid, r = mid - 1;
		}
		
		printf("%lld\n", ans);
	}
	
	return 0;
}

Imbalanced Arrays

给定一个序列 a1n ,构造一个序列 b1n 满足

  • nbin,bi0
  • i,j[1,n],bi+bj0
  • 满足有 aij 满足 bi+bj>0i,j 可以相等)

若不存在这个序列输出 NO

首先可以注意到若序列中同时出现或同时不出现 0n ,则无解

于是我们可以从极端情况入手,用左右两个指针维护即可

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;

struct Node {
	int a, b, id;
	
	inline bool operator < (const Node &rhs) const {
		return a < rhs.a;
	}
} a[N];

int ans[N];

int T, n;

inline bool solve() {
	for (int i = n, l = 1, r = n, tmp = 0; i; --i) {
		if (a[l].a == tmp && a[r].a - i == tmp)
			return false;
		
		if (a[l].a != tmp && a[r].a - i != tmp)
			return false;
		
		if (a[l].a == tmp)
			a[l].b = -i, ++l;
		else
			a[r].b = i, ++tmp, --r;
	}
	
	for (int i = 1; i <= n; ++i)
		ans[a[i].id] = a[i].b;
	
	return true;
}

signed main() {
	scanf("%d", &T);
	
	for (; T; --T) {
		scanf("%d", &n);
		
		for (int i = 1; i <= n; ++i) {
			scanf("%d", &a[i].a);
			a[i].id = i;
		}
		
		sort(a + 1, a + 1 + n);
		
		if (solve()) {
			puts("YES");
			
			for (int i = 1; i <= n; ++i)
				printf("%d ", ans[i]);
				
			puts("");
		} else
			puts("NO");
	}
	
	return 0;
}

Ina of the Mountain

定义一次操作为选定 l,r ,将 alr 自减,操作过程中若 ai=0aik ,求使得所有 ai 均等于 k 的最小操作次数

ciai 被区间覆盖的次数,则 i[1,n],aici(modk)

bi=aiai1,di=cici1 ,则 i[1,n],bidi(modk) ,可以证明存在一组最优解满足所有 di(k,k)

这样一来,每个 di 只有两种取值,设为 Ai<0,Bi>0 。选 Ai 不会产生代价,选 Bi 会产生 Bi 的代价,且各段前缀中选的数的和要非负

使用小根堆维护反悔贪心即可,时间复杂度 O(nlogn)

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 7;

int a[N];

int T, n, K;

signed main() {
	scanf("%d", &T);
	
	for (; T; --T) {
		scanf("%d%d", &n, &K);
		
		for (int i = 1; i <= n; ++i)
			scanf("%d", a + i);
		
		ll ans = 0;
		priority_queue<int, vector<int>, greater<int> > Q;
		
		for (int i = 1, sum = 0; i <= n; ++i) {
	        int b = (a[i] - a[i - 1] + K) % K;
	
	        if (!b)
	            continue;
	
	        int x = b - K;
	
	        if (sum + x >= 0)
	            sum += x, Q.push(b);
	        else {
	            int num = Q.empty() ? inf : Q.top();
	
	            if (num < b)
	                ans += num, Q.pop(), Q.push(b), sum += x + K;
	            else
	                ans += b, sum += b;
	        }
	    }
	    
	    printf("%lld\n", ans);
	}
	
	return 0;
}

Miriany and Matchstick

A,B 填充一个 2×n 的矩阵,第一行已填好,求使得相邻两格相同的格子对数量为 k 的填的方案数

fi,c,j 表示填了第二行的前 i 个位置,i 处的字符为 c{A,B} (用 0,1 表示 A,B ,填有不同字符的相邻位置是否能有 j

打表发现 i[1,n],c{0,1} ,有 fi,c,0,fi,c,1, 构成的 01 串中所有 1 构成一个极长连续段或构成两个极长连续段且中间最多一个 0

令三元组 (p,l,r) 表示一个状态,其中 p 为空缺位置, l,r 表示最左或最右的 1 的位置,转移即可

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 7;

struct Node {
    int p, l, r;
    
    inline bool check(int x) const {
        return l <= x && x <= r && x != p;
    }
    
    inline Node getnxt(int d) const {
        return Node{~p ? p + d : -1, l + d, r + d};
    }
} f[N][2];

int a[N], b[N];
char s[N];

int T, n, k;

inline Node merge(const Node &lhs, const Node &rhs) {
    int L = min(lhs.l, rhs.l), R = max(lhs.r, rhs.r);

    if (L <= lhs.p && lhs.p <= R && !rhs.check(lhs.p))
        return (Node) {lhs.p, L, R};
	else if (L <= rhs.p && rhs.p <= R && !lhs.check(rhs.p))
        return (Node) {rhs.p, L, R};
	else if (lhs.r + 2 == rhs.l)
        return (Node) {lhs.r + 1, L, R};
	else if (rhs.r + 2 == lhs.l)
        return (Node) {rhs.r + 1, L, R};
	else
		return (Node) {-1, L, R};
}

signed main() {
	scanf("%d", &T);

    for (; T; --T) {
    	scanf("%d%d%s", &n, &k, s + 1);
    	
    	for (int i = 1; i <= n; ++i)
	        a[i] = s[i] == 'B';
	
	    for (int i = 2; i <= n; ++i)
	        k -= a[i] != a[i - 1];
	
	    if (k < 0) {
	    	puts("NO");
	    	continue;
	    }
	
	    f[1][0] = Node{-1, 0, 0}, f[1][1] = Node{-1, 1, 1};
	
	    for (int i = 2; i <= n; ++i)
	        if (a[i - 1] == a[i]) {
	            f[i][0] = merge(f[i - 1][1].getnxt(1), f[i - 1][0]);
	            f[i][1] = merge(f[i - 1][0].getnxt(2), f[i - 1][1].getnxt(1));
	        } else {
	            f[i][0] = merge(f[i - 1][0].getnxt(1), f[i - 1][1]);
	            f[i][1] = merge(f[i - 1][1].getnxt(2), f[i - 1][0].getnxt(1));
	        }
	
	    int p = k, cnt;
	
	    if (f[n][0].check(k))
	        cnt = 0;
	    else if (f[n][1].check(k))
	        cnt = 1;
	    else {
	    	puts("NO");
	    	continue;
	    }
	
	    for (int i = n; i; --i) {
	        b[i] = a[i] ^ cnt;
	
	        if (i > 1)
		        if (a[i - 1] == a[i]) {
		            if (cnt) {
		                if (f[i - 1][0].check(p - 2))
		                    p -= 2, cnt = 0;
		                else
		                    --p;
		            } else {
		                if (f[i - 1][1].check(p - 1))
		                    --p, cnt = 1;
		            }
		        } else {
		            if (cnt) {
		                if (f[i - 1][1].check(p - 2))
		                    p -= 2;
		                else
		                    --p, cnt = 0;
		            } else {
		                if (f[i - 1][0].check(p - 1))
		                    --p;
		                else
		                    cnt = 1;
		            }
		        }
	    }
	    
    	puts("YES");

	    for (int i = 1; i <= n; ++i)
	        putchar(b[i] ? 'B' : 'A');
	
	    puts("");
    }

    return 0;
}
posted @   浣辰  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示