以下是我在平时在做ACM练习时的一些心得体会,只是把自己的一些总结和想法分享一下。我写的东西也不知道是不是真的有价值,或许在大佬看来只是一个非常不成熟的想法(缺少社会的毒打.jpg)。
我们在构造或维护一个有特殊意义的数据结构的时候,往往可以不从改数据结构的“定义”入手,而从该数据结构的“性质”入手来构造或维护它。
举个线性代数上的例子,如果我们想维护一个正定二次型矩阵,我们可以不必要求每次维护完毕后该矩阵都能满足正定二次型的定义(若对任何非零向量x,实二次型f(x)如果对任何x≠0都有f(x)>0,则称f为正定二次型,并称矩阵A是正定的,记之A>0。),我们只需要让这个矩阵维护完毕后都能满足正定二次型的“性质”(判断该矩阵的所有所有顺序主子式是否全大于零或者判断该矩阵的正惯性系数是否等于n)即可。
举个数据结构上的例子,当我们在维护一颗红黑树的时候(红黑树的各种基本操作),我们只要求维护结束后不违反红黑树的性质(规则)就好。关于红黑树的性质,如下
只要满足这些规则,那这棵树就是红黑树,也就是一个二叉平衡树(满足定义)。
所以,当定义与性质互为充要条件时,我们只要让所求目标满足性质即能符合定义。这是一个简单的逻辑思维,但有时候可以给求解带来一些便利,或者提供一个新思路。
求解一些需要我们构造数列或者特殊数据结构的题目时,我们可以先观察出目标数据结构的性质,构造出“满足性质”的数据结构,有时这个数据结构即为所求。
比如题目977D - Divide by three, multiply by two 大致的题意为,将给定的数vi进行排列,构造出一个数列ai,使得a[i+1]=a[i]/3或者a[i+1]=a[i]*2。这题乍一看可以由普通搜索来做,我称这种做法为构造出满足“定义”的目标数列。我们也可以从目标数列的性质入手,来解决这个问题。设deg3(x)为x最大能被3整除的次数,如deg(3)=1,deg(9)=2,deg(13)=0。对于目标数列ai,我们可以观察到deg(a[i])≥ deg(a[i+1]),而且如果deg(a[i])= deg(a[i+1]),则a[i]<a[i+1]。这就是答案的性质。这样我们就可以以deg(vi)为第一比较准则,以vi的值为第二比较准则,进行一次排序,排序的结果即为答案。这就是以构造出满足性质的数列,来得到满足定义的数列的做法。
题解代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int count3(LL x){
int ret=0;
while(x % 3 == 0){
ret++;
x /= 3;
}
return ret;
}
int n;
vector<pair<int,LL>> v;
int main(){
cin>>n;
v.resize(n);
for(int i=0; i<n; i++){
cin>>v[i].second;
v[i].first=-count3(v[i].second);
}
sort(v.begin(), v.end());
for(int i=0; i<n; i++)
printf("%lld%c", v[i].second, " \n"[i + 1 == n]);
}
这大概是一种解题的方向或思维方式吧,是我最近学习的一次小总结,希望能有点用。第一次正正经经地写博客,若有写的不好的地方请大佬们指教。
以上。