1. 程式人生 > >ACM中的幾個小技巧(離散化,尺取法,資料預處理)

ACM中的幾個小技巧(離散化,尺取法,資料預處理)

離散化
使用STL演算法離散化:
思路:先排序,再刪除重複元素,然後就是索引元素離散化後對應的值。
假定待離散化的序列為a[n],b[n]是序列a[n]的一個副本,則對應以上三步為:

sort(sub_a,sub_a+n);
int size=unique(sub_a,sub_a+n)-sub_a;//size為離散化後元素個數
for(i=0;i<n;i++)
a[i]=lower_bound(sub_a,sub_a+size,a[i])-sub_a + 1;
//k為b[i];

    ```


經離散化後對應的值
對於第3步,若離散化後序列為0, 1, 2, ..., size - 1
則用lower_bound,從1, 2, 3, ..., size則用upper_bound,其中lower_bound返回第1個不小於b[i]的值的指標,而upper_bound返回第1個大於b[i]的值的指標,當然在這個題中也可以用lower_bound然後再加1得到與upper_bound相同結果,兩者都是針對以排好序列。使用STL離散化大大減少了程式碼量且結構相當清晰。 **尺取法** 給定長度為n的數列整數a0,a1,a2,a3 ..... an-1以及整數S。求出綜合不小於S的連續子序列的長度的最小值。如果解不存在,則輸出0。   10 < n< 10 ^ 50 < a i < 10
^4 S<10^8 這裡我們拿第一組測試資料舉例子,即 n=10, S = 15, a = {5,1,3,5,10,7,4,9,2,8} ![](http://images.cnitblog.com/blog/597004/201408/291224259702079.jpg) 1.初始化左右端點 2.不斷擴大右端點,直到滿足條件 3.如果第二步中無法滿足條件,則終止,否則更新結果 4.將左端點擴大1,然後回到第二步 例題:poj 3320 尺取法+Map `` #include <map> #include <queue> #include <cmath> #include <cstdio>
#include <cstring> #include <iostream> #include <algorithm> #define maxn 100005 #define MOD 1000000007 #define inf 0x3f3f3f3f typedef long long ll; using namespace std; int n,m,k; int a[maxn]; int main(){ while(~scanf("%d",&n)){ map<int,int>Hash,cnt; for(int i = 0;i<n;i++){ scanf("%d",a+i); Hash[a[i]]++; } int tot = Hash.size(); int tag = 1; int s = 0,e = 0; int ans = inf; while(tag){ while(cnt.size()<tot && e<n) cnt[a[e++]]++; if(cnt.size()<tot) {tag=0;break;} ans = min(ans,e-s); cnt[a[s]]--; if(cnt[a[s]]==0) cnt.erase(a[s]); s++; } printf("%d\n",ans); } return 0; }

資料預處理
以HDU 5073 鞍山D為例。
主要是針對區間的求和,平方這類的預處理
ans=min(ans,xix0)2+x202x0xi)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 51000
using namespace std;
double sum1,sum2;
double pos[maxn];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i = 1;i<=n;i++)
            scanf("%lf",pos+i);
        if(n==k){puts("0");continue;}
        sort(pos+1,pos+1+n);
        sum1 = sum2 = 0;
        int m = n-k;
        for(int i = 1;i<m;i++){
            sum1 += pos[i];
            sum2 += pos[i] * pos[i];
        }
        double ans = 1e100;

        for(int i = m;i<=n;i++){
            sum1 += pos[i];
            sum2 += pos[i]*pos[i];
            double mid = sum1 / m;
            double tmp = sum2 + m*mid*mid - 2*mid*sum1;
            ans = min(ans,tmp);
            sum1 -= pos[i-m+1];
            sum2 -= pos[i-m+1] * pos[i-m+1];
        }
        printf("%.12f\n",ans);
    }
    return 0;
}