推荐阅读:Codeforces Round 939 (Div. 2)(A-D) - 知乎
状压:
18个数,可以状压。
因为无法确定哪种方案最后和最大。
举例:
0 0 0 5 0 0
你说是一起呢,还是左右各自弄呢?
递归:
这是一个“有规律的”过程:
0 0 0 0
0 0 0 1
0 0 2 2
0 0 0 2
0 0 1 2
0 3 3 3
0 0 0 3
0 0 1 3
0 2 2 3
0 0 2 3
0 1 2 3
4 4 4 4
————
观察:
0 0 0 0
0 0 0 1
0 0 2 2
0 0 0 2
0 0 1 2
0 3 3 3
0 0 0 3
0 0 1 3
0 2 2 3
0 0 2 3
0 1 2 3
4 4 4 4
感觉可以递归,但是递归非常难想。同时又想不出其他办法。
可以直接看代码理解:
0.ptr就是最后打印的步骤,我们可以先存起来,这样就知道有多少步了。
1. 调用前先清零,浪费步骤就浪费了,步数是足够多的。检查如果有0,那么我们对总体操作是不会变为0的,那就对总体操作两次。
2. 调用,看我们上述过程,其实是右往左这么一个过程。(必须先搞出来大的数)
3. op(l +1, r ) ; 就是向右的一个过程。退出来的时候就是向左。
我们让这个出来后符合顺序。
只有一位时,已经满足了,对这个“整体”操作即可。(何尝不是一个整体)
当只有两位时也已经满足,多位就有关我们后面的操作了。
既然两位时已经满足 0 1,符合顺序mex,那就对他们操作成为 2 2 吧。
然后接下来我们希望最后一个2 的 左边也是顺序呀,我们的l正好能到1的位置哦。而前面都是0,。(是不是某种巧合。可以模拟一下)
(出题人讲的是从左往右倒着来的,整体思路一样,不过没有说的很透彻【官方讲解】Codeforces Round 939 (Div. 2)_哔哩哔哩_bilibili)
4. 最大后,如果是结束(cl,cr在调用前就赋值了),那就退出了。
否则得接着操作,仍旧参照上述过程,可以发现左边清零成为子问题接着搞就可以。
vector<PII>prt;
int cl, cr;
void op(int l, int r)
{
if (l == r)
{
prt.emplace_back(l, r);
return;
}
op(l + 1, r);//出来就是顺序啦
prt.emplace_back(l, r);
if (l == cl && r == cr) return;
prt.emplace_back(l, r-1);
op(l, r - 1);
}
参考代码:
也是学到了emplace_back的效率高点。
注意emplace_back特殊类型(比如pair<int,int>)不需要初始化列表{},直接括号里写多个值就可以了。
#define ll long long
#define endl "\n"
#define PII pair<int,int>
#define int long long
const int maxn = 2e3 + 5;
int arr[maxn];
vector<PII>prt;
int cl, cr;
void op(int l, int r)
{
if (l == r)
{
prt.emplace_back(l, r);
return;
}
op(l + 1, r);//出来就是顺序啦
prt.emplace_back(l, r);
if (l == cl && r == cr) return;
prt.emplace_back(l, r-1);
op(l, r - 1);
}
void solve()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> arr[i];
}
int ans = 0;
int mask = 0;
for (int i = 0; i < (1<<n); i++)
{
int cursum = 0;
for (int l = 0; l < n; l++)
{
if ((i >> l) & 1)
{
int r = l;
while (((r+1) < n) &&((i >> (r+1)) & 1))
{
r++;
}
cursum += (r - l + 1) * (r - l + 1);
l = r;
}
else cursum += arr[l];
}
if (cursum > ans)
{
ans = cursum;
mask = i;
}
}
for (int l = 0; l < n; l++)
{
if ((mask >> l) & 1)
{
int r = l;
bool zero = arr[l] == 0;
while ((r + 1 < n) && ((mask >> (r+1)) & 1) )
{
r++;
zero |= arr[r] == 0;
}
if (zero)
prt.emplace_back(l + 1, r + 1);
prt.emplace_back(l+1, r+1);
cl = l + 1, cr = r + 1;
op(l+1, r+1);
l = r;
}
}
cout << ans << " ";//<< cnt << endl;
cout << prt.size() << endl;
for (auto p : prt)
{
cout << p.first << " " << p.second << endl;
}
}