日常刷题2023-3-11

日常刷题2023-3-11

经验+1

判断一个数是完全平方数的方法是先开方,用得到的结果再求平方看能否得到原数。

经验+1

思考问题要从易到难,不要一开始就去想一些及其复杂的情况。

D - Swap to Gather

棕色

https://atcoder.jp/contests/abc393/tasks/abc393_d

思路:递推

简单思考一下样例发现是不能贪心的,并不能保证一定是全部移动到中间最优。既然不能贪心那么我们就只能枚举所以1聚集的位置。枚举就是\(O(n)\)的复杂度了,意味着我们只能\(O(1)\)的计算移动次数。

我们发现了一个递推关系,假设我们现在枚举的聚集位置是 i ,且全部移动到 i 位置需要 x 次操作。思考一下枚举到 i + 1 时会发生什么,所以 i 位置右边的 1 都会减少移动 1 次,所有 i 位置左边,包括 i 位置的数都会多移动一次。所以移动到i+1位置需要操作 \(x - (i 右边1的个数) + (i 左边包括 i 位置 1 的个数)\)

所以我们只要提前算出聚集到 1 位置的操作次数,我们就可以递推的求出所以情况。由于我们是把所有数聚集到一个位置,跟题目有所偏差,统计答案是需要把聚集到一起的 1 分散一下,把多用的操作次数减掉

经验+1

没有明显贪心策略的题目求最值,基本上只能靠枚举所以情况。毕竟计算机最擅长的就是重复枚举

代码

#include <bits/stdc++.h>

typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;

#define int long long

int cul(int x){
	return (1+x)*x/2;
}

void solve(){
	int n; std::cin >> n;
	std::string s; std::cin >> s;
	s = " " + s;

	std::vector<int> pre(n+1);
	for (int i = 1; i <= n; i++){
		pre[i] += pre[i-1] + (s[i] == '1');
	}

	int ans = 0;
	for (int i = 1; i <= n; i++){
		if (s[i] == '1'){
			ans += i - 1;
		}
	}

	int t = pre[n] - pre[1];
	if (s[1] == '0') t--;

	int res = ans - cul(t);
	for (int i = 2; i <= n; i++){
		int j = i - 1;
		int front = pre[j];
		int back = pre[n] - pre[j];

		ans += front;
		ans -= back;
		if (back > 0) back--;
		else front--;
		res = std::min(ans-cul(front)-cul(back), res);
	}

	std::cout << res << '\n';
}

signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
	int t = 1, i;
	for (i = 0; i < t; i++){
		solve();
	}
	return 0;
}

树状数组求Lis

可以做到$O(n log n) $

#include <bits/stdc++.h>

typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;

// 维护最大值的树状数组
std::vector<int> bit(7);

void add(int x, int k){
	for (; x <= 6; x += x & -x) bit[x] = std::max(bit[x], k);
}

int ask(int x){
	int res = 0;
	for (; x; x -= x & -x) res = std::max(res, bit[x]);
	return res;
}

void solve(){
	std::vector<int> a{0, 9, 4, 5, 6, 1, 7};
	std::vector<int> dp(7);

	for (int i = 1; i <= 6; i++){
		int ans = ask(a[i]-1) + 1; // 小于等于a[i]-1的数中Lis的最大值 + 1
		std::cout << ans << ' ';
		add(a[i], ans); // 把以a[i]结尾的Lis的最值加到树状数组中维护。
	}

}

signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
	int t = 1, i;
	for (i = 0; i < t; i++){
		solve();
	}
	return 0;
}

航线

铜牌

思路:状态图最短路

把四种方向当作四种状态,跑Dijkstra算法。

代码用到了把二维坐标转化为一维坐标的方法。

代码

#include <bits/stdc++.h>

typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define MOD 998244353
using i64 = long long;
const int N = 100010;
const i64 inf = 1ll << 60 - 1;
const int dx[4]={0,-1,0,1};
const int dy[4]={1,0,-1,0};


int n, m;
std::vector<int> d(N), t(N);
std::vector dis(N, std::vector<i64>(4));
std::vector vis(N, std::vector<bool>(4));

int Encode(int x, int y){return (x-1)*m+y;}
pii Decode(int id){return std::make_pair((id-1)/m+1, (id-1)%m+1);}

void solve(){
	std::cin >> n >> m;
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= m; j++){
			std::cin >> t[Encode(i, j)];
		}
	}
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= m; j++){
			std::cin >> d[Encode(i, j)];
		}
	}

	int st = Encode(1, 1), td = Encode(n, m);
	for (int i = 1; i <= n*m; i++){
		for (int j = 0; j < 4; j++){
			dis[i][j] = inf;
			vis[i][j] = 0;
		}
	}
	std::priority_queue<std::tuple<i64, int, int>,
			std::vector<std::tuple<i64, int, int>>,
			std::greater<std::tuple<i64, int, int>>> q;

	q.push({0, st, 0}); dis[st][0] = t[st];
	while (!q.empty()){
		auto [val, p, u] = q.top(); q.pop();
		if (vis[p][u]) continue;
		vis[p][u] = 1;

		for (int v = 0; v < 4; v++){
			if (dis[p][u] + d[p] >= dis[p][v]) continue;
			dis[p][v] = dis[p][u] + d[p];
			q.push({dis[p][v], p, v});
		}

		auto [x, y] = Decode(p);
		x += dx[u]; y += dy[u];
		int to = Encode(x, y);
		auto OutMap=[&](int x, int y){
			return x<1||x>n||y<1||y>m;
		};
		if (!OutMap(x, y)&&dis[p][u]+t[to]<dis[to][u]){
			dis[to][u]=dis[p][u]+t[to];
			q.push({dis[to][u], to, u});
		}
	}

	std::cout << dis[td][3] << '\n';
}

signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
	int t = 1, i;
	std::cin >> t;
	for (i = 0; i < t; i++){
		solve();
	}
	return 0;
}
posted @ 2025-03-11 09:22  califeee  阅读(13)  评论(0)    收藏  举报