1. 程式人生 > 其它 >sklearn-機器學習庫

sklearn-機器學習庫

前言

(什麼時候我也開始寫前言了

昨天的講課內容包括CDQ分治……
有一說一,有點像紙人套幻覺套祕偶套分身套歷史投影的某套娃大師·占卜家序列。
CDQ分治每一次劃分出來兩個子問題,前一個子問題用來解決後一個子問題。主要用來解決偏序問題。
使用CDQ分治時要注意題目要求:修改操作對詢問的貢獻獨立,互不影響;允許使用離線演算法。

三維偏序

題目:

P3810 【模板】三維偏序(陌上花開

題目描述:

有 $ n $ 個元素,第 $ i $ 個元素有 $a_i,b_i,c_i $三個屬性,設 $ f(i) $ 表示滿足 $a_j ≤ a_i $ 且 $ b_j ≤ b_i $且 $ c_j ≤ c_i $且 \(j≠i\)

\(j\) 的數量。

對於 \(d∈[0,n)\) 求 $ f(i)=d $ 的數量。

抽象理解就是:對於一個元素\(i\) 來說,\(f(i)\) 指 ,三種屬性都比\(i\)菜的元素的數量。

那麼二維偏序指 :對於一個元素\(i\) 來說,\(f(i)\) 指 ,兩種屬性都比\(i\)菜的元素的數量。

那麼一維偏序指: 對於一個元素\(i\) 來說,\(f(i)\) 指 ,一種屬性比\(i\)菜的元素的數量。

一維偏序

細品一下剛剛順下來的一維偏序的定義。
每個元素有一個權值,我們要找有幾個權值比某元素小的
於是這就成了比大小的排序問題。
所以一維偏序就是那什麼排序。

歸併排序

至於為什麼是歸併排序而不是什麼氣泡排序,快速排序……因為說的是(CDQ)分治嘛
至於為什麼不用平衡樹,樹狀陣列,權值線段樹等可以查詢排名的資料結構……後面套娃會用到
(這裡就不細講歸併排序的原理了)
程式碼:


#define mid ((l+r)>>1)
void gbpx(int l,int r,int *a){//閉區間,a是那個亂七八糟沒排序的原始數列 
	if(l==r)return ;
	gbpx(l,mid,a);gbpx(mid+1,r,a);
	int t1=l,t2=mid+1;
	for(int i=l;i<=r;i++)
		if((a[t1]<a[t2] && t1<=mid) || t2>r)b[i]=a[t1++];
		else b[i]=a[t2++];
	for(int i=l;i<=r;i++) a[i]=b[i];
}

二維偏序

對於二維偏序,就一下子想到了類似的問題:求逆序對
求逆序對問題的兩個元素屬性分別是:位置和權值,求每個元素比
它位置小,且比它權值大的元素個數(和)
同理,只需要在程式碼上進行一些改動。

例題傳送:

P1908 逆序對

程式碼實現:

快讀不用也可以過,如果要用我(嫖水哥)的這個快讀的話,要開c++11.

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+105;
int a[N],b[N],n;
long long ans;
void CDQ(int l,int r,int *a){
	if(l==r) return ;
	int mid=(l+r)>>1;
	CDQ(l,mid,a);CDQ(mid+1,r,a);
	int t1=l,t2=mid+1;
	for(int i=l;i<=r;i++)
		if(a[t1]>a[t2] && t2<=r || t1>mid) b[i]=a[t2++],ans+=mid-t1+1;
		else b[i]=a[t1++];
	for(int i=l;i<=r;i++)a[i]=b[i];
}
namespace Read{
    template<typename T>
    inline void read(T &x){
        x=0;T f=1;char ch=getchar();
        while (!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
        while (isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
        x*=f;
    }

    template <typename T, typename... Args>
    inline void read(T& t, Args&... args) {
        read(t); read(args...);
    }
}
using namespace Read;
int main(){
	read(n);
	for(int i=1;i<=n;i++)read(a[i]);
	CDQ(1,n,a);
	printf("%lld",ans);
	return 0;
}

那麼話歸正題:

三維偏序

(題目傳送在上面)

程式碼實現:

#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
const int N=1e5+105;
int n,k,cnt,d[N<<1],ans[N];
//結構體部分 
struct node{int A,B,C,sz,ans;}a[N],b[N];
inline bool cmp1(node a,node b){
	if(a.A!=b.A) return a.A<b.A;
	if(a.B!=b.B) return a.B<b.B;
	return a.C<b.C;
}//第一維排序 
inline bool cmp2(node a,node b){return a.B<b.B;}
//樹狀陣列部分 
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int v){for(;x<=k;x+=lowbit(x))d[x]+=v;}
inline int query(int x){
	int res=0;
	for(;x;x-=lowbit(x))res+=d[x];
	return res;
}
//CDQ分治部分 
void CDQ(int l,int r){
	if(l==r) return ;
	CDQ(l,mid);CDQ(mid+1,r);
	sort(a+l,a+mid+1,cmp2);sort(a+mid+1,a+r+1,cmp2);
	//分割槽間排序 
	int t1=l,t2=mid+1;
	for(int i=t2;i<=r;i++){
		while(a[i].B>=a[t1].B && t1<=mid){add(a[t1].C,a[t1].sz);t1++;}
		a[i].ans+=query(a[i].C);
	}
	for(int i=l;i<t1;i++)add(a[i].C,-a[i].sz);//要記得清空陣列 
}
namespace Read{
    template<typename T>
    inline void read(T &x){
        x=0;T f=1;char ch=getchar();
        while (!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
        while (isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
        x*=f;
    }

    template <typename T, typename... Args>
    inline void read(T& t, Args&... args) {
        read(t); read(args...);
    }
}
using namespace Read;
int main(){
	read(n,k);
	for(int i=1;i<=n;i++)read(b[i].A,b[i].B,b[i].C);
	//合併同類項 
	sort(b+1,b+1+n,cmp1);
	for(int i=1;i<=n;i++)
		if(b[i].A!=b[i-1].A || b[i].B!=b[i-1].B || b[i].C!=b[i-1].C)a[++cnt]=(node){b[i].A,b[i].B,b[i].C,1};
		else a[cnt].sz++;
	//CDQ 
	CDQ(1,cnt);
	for(int i=1;i<=cnt;i++)ans[a[i].ans+a[i].sz-1]+=a[i].sz;
	for(int i=0;i<n;i++)printf("%d\n",ans[i]);
	return 0;
}		

座右銘:我從來沒有見過這樣陰鬱而又光明的日子。