「暑期训练」「Brute Force」 Money Transfers (CFR353D2C)

题目

分析

这个Rnd353真是神仙题层出不穷啊,大力脑筋急转弯- -
不过问题也在我思维江化上。思考任何一种算法都得有一个“锚点”,就是说最笨的方法怎么办。为什么要这么思考,因为这样思考最符合我们的思维规律。然后从这种最笨的方法中找问题、找漏洞、找关键的变量不变量,就能转化出更好的更快的算法。
这题就是这样。最笨的方法是什么?随便从哪个点出发,按照一个方向一个一个抹平差距。可以保证,n-1次一定完成。那么哪里可以改进?0区间。0区间的时候我们可以不移动:比如说 0 0 2 -2 0 0,那么只需要移动一次就可以了。那么是不是所有的0区间都可以不考虑?不可以(自己比划一下就知道了)。因此,我们需要找到最大的0区间。那么成环的问题要不要考虑?得看算法。这个算法太神奇了,我们好好分析一下。

代码

#include <bits/stdc++.h>
#define MP make_pair
#define PB push_back
#define fi first
#define se second
#define ZERO(x) memset((x), 0, sizeof(x))
#define ALL(x) (x).begin(),(x).end()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define per(i, a, b) for (int i = (a); i >= (b); --i)
#define QUICKIO                  \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0);
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pi = pair<int, int>;
using pii = pair<int, pi>;

template<typename T>
T read()
{
    T tmp; cin>>tmp;
    return tmp;
}

int main()
{
    int n; ll sum=0;
    cin>>n;
    map<ll,int> m;
    int maxinterval=0;
    rep(i,1,n)
    {
        int tmp; cin>>tmp;
        sum+=tmp;
        maxinterval=max(maxinterval,++m[sum]);
    }

    cout<<n-maxinterval<<endl;

    return 0;
}

算法分析

问题就在于m[x]到底是什么。
我们考虑这三种情况的数组:
1. 0 1 -1 0
2. 1 0 -1 0
3. 1 0 0 -1
这三种情况下m[x]的值分别是什么?
1. m[0]=3, m[1]=1
2. m[1]=2, m[0]=2
3. m[1]=3, m[-1]=1
也就是说,m[x]维护的是区间前若干个数(也就是说这些数不属于区间)的和为x的区间,这样的区间的总长度。
更直观的是这样的数组:
0 1 0 -1 0 0 0 0 1 0 -1 0
m[x]分别为:m[0]=7,m[1]=4
0 1 0 -1 0 0 0 0 2 0 -2 0
m[x]分别为:m[0]=7,m[1]=2,m[2]=2
那么为什么我们要找最大的m[x]?在下面两个例子中,我们取的并不是单个的区间,但是仍然达到了最优解。
很简单,这样的区间保证了这样一个性质:第一个数一定不是0,其他数一定是0(如果第一个数是0,那么区间可以更长)。这样一来,我们总可以保证,不属于区间的数字,最后一定可以通过操作抹到0上。这样的操作不会跨越区间(什么意思呢?比如说… x1 0 0 0 2 -1 x2 0 0 0 0 …,我们设x1代表的区间和x2代表的区间一致,那么,会不会出现这样一种情况:2和-1的操作不能在x1和x2的区间内完成,它们必须要“借”别的区间的值),因为如果跨越区间了,就会导致区间和的性质被破坏了:它总保证前面的和为x(这就意味着,在区间外必有了x->x,也就是说它们是“平”的)!因此,一定能在区间之间,完成抹0的操作。
这样,我们找到最大的m[x],问题就得以解决了。
我不知道我有没有讲明白,但是感觉自己吹了一遍明白这个算法的思路了23333另外这题我觉得还是属于暴力的,因为确实还是要穷举找最大嘛23333就是其他地方的思维量大了一些

官方题解

We have array ai and should make all numbers in it be equal to zero with minimal number of operations. Sum of all ai equals to zero.

We can divide array into parts of consecutive elements with zero sum. If part has length l we can use all pairs of neighbours in operations and make all numbers be equal to zero with l - 1 operations.

So, if we sum number of operations in each part we get ans = n - k where k is number of parts. We should maximize k to get the optimal answer.

One of the part consists of some prefix and probably some suffix. Each of other parts is subarray of a.

Let’s calculate prefix sums. Each part has zero sum so prefix sums before each part-subarray are the same.

So we can calculate f — number of occurencies of the most frequent number in prefix sums and answer will be equal to n - f.
之后补分析。

猜你喜欢

转载自blog.csdn.net/qq_17632793/article/details/81256508