1. 程式人生 > >【小總結】用答案的性質來求解一些ACM題目

【小總結】用答案的性質來求解一些ACM題目

    以下是我在平時在做ACM練習時的一些心得體會,只是把自己的一些總結和想法分享一下。我寫的東西也不知道是不是真的有價值,或許在大佬看來只是一個非常不成熟的想法(缺少社會的毒打.jpg)。

   我們在構造或維護一個有特殊意義的資料結構的時候,往往可以不從改資料結構的“定義”入手,而從該資料結構的“性質”入手來構造或維護它。

    舉個線性代數上的例子,如果我們想維護一個正定二次型矩陣,我們可以不必要求每次維護完畢後該矩陣都能滿足正定二次型的定義(若對任何非零向量x,實二次型f(x)如果對任何x0都有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]);
}

    這大概是一種解題的方向或思維方式吧,是我最近學習的一次小總結,希望能有點用。第一次正正經經地寫部落格,若有寫的不好的地方請大佬們指教。

   以上。