zoukankan      html  css  js  c++  java
  • agc037_c Numbers on a Circle

    题目叙述

    Link

    给出一个填满数字的环,求最少变换多少次能变换为另一个环。

    每次可以进行如下变换:

    • 将一个数换为左边一个和右边有个数还有自己的和。

    题解

    考虑倒着做。下面 a[i] 为原始环,b[i] 为最终环

    原操作相当于 a[i]+=a[i-1]+a[i+1] ,所以倒着做相当于 b[i]-=b[i-1]+b[i+1] ,也就是减掉相邻两个数。

    那么考虑 b 的最大与对应位置 a 不相等的数,如果不进行 b[i]-=b[i-1]+b[i+1] ,那么他两边的数必然不能改变,所以他也不能改变。所以必然他先改变。变到恰好大于等于 a[i] 即可。但如果恰好比 a[i] 大的时候仍然比 b[i-1]+b[i+1] 大,那么无解。

    所以使用堆维护所有没有变成正确数值的位置即可。

    代码

    #include <cstdio>
    #include <queue>
    #define int long long
    using namespace std;
    const int NC = 2e5 + 5;
    int N, A[NC], B[NC];
    int pre(int i) { return (i == 1) ? N : (i - 1); }
    int nxt(int i) { return (i == N) ? 1 : (i + 1); }
    struct cmp {
    	bool operator()(const int &x, const int &y) { return B[x] < B[y]; }
    };
    priority_queue<int, vector<int>, cmp> H;
    signed main() {
    	freopen("circle.in", "r", stdin);
    	scanf("%lld", &N);
    	for (int i = 1; i <= N; ++i) scanf("%lld", &A[i]);
    	for (int i = 1; i <= N; ++i) scanf("%lld", &B[i]);
    	for (int i = 1; i <= N; ++i) if (A[i] != B[i]) H.push(i);
    	int ans = 0;
    	while (H.size()) {
    		int tp = H.top();
    		H.pop();
    		int dec = (B[tp] - A[tp]) / (B[pre(tp)] + B[nxt(tp)]);
    		if (dec == 0 && B[tp] != A[tp]) {
    			printf("-1
    ");
    			return 0;
    		}
    		B[tp] -= dec * (B[pre(tp)] + B[nxt(tp)]);
    		ans += dec;
    		if (B[tp] != A[tp])
    			H.push(tp);
    	}
    	printf("%lld
    ", ans);
    	fclose(stdin);
    	return 0;
    }
    //这也要开 long long
    
  • 相关阅读:
    Android调用Webserive
    SSD算法思想和结构详解
    第五章-一起看决策树如何做出决策?
    第四章-朴素贝叶斯朴素吗?
    第三章-KNN(分类和回归算法模型)
    第二章-感知机
    第一章-统计学习方法概论
    c语言 宏定义和全局变量,认识循环语句
    运算符注意事项
    c语言的scanf函数注意事项
  • 原文地址:https://www.cnblogs.com/YouthRhythms/p/13544062.html
Copyright © 2011-2022 走看看