謝允恆
分而治之
切割到規模夠小時會有一定的特性能解決子問題
觀察問題的性質
將子問題的答案回推至大問題
以求出最大值為例
1 | 7 | 5 | 6 | 2 | 3 | 8 | 4 |
---|
1 | 7 | 5 | 6 |
---|
2 | 3 | 8 | 4 |
---|
1 | 7 |
---|
5 | 6 |
---|
2 | 3 |
---|
8 | 4 |
---|
1
7
5
6
2
3
8
4
一個數裡的最大值肯定是自己
以求出最大值為例
1
7
5
6
2
3
8
4
7
6
3
8
7
8
8
好耶答案
(不過誰會拿基礎的分治來求最大值)
#include<iostream> using namespace std; const int N=5e5+30; int a[N]; int DnC(int l,int r){ if(l==r) return a[l]; int mid=(l+r)/2; return max(DnC(l,mid),DnC(mid+1,r)); } int main(){ int n; cin>>n; for(int i=0;i<n;i++){ cin>>a[i]; } cout<<DnC(0,n-1)<<"\n"; }
左閉右閉
Merge sort
欸不對,怎麼合併
1 | 5 | 6 | 7 |
---|
2 | 3 | 4 | 8 |
---|
A
B
1
2
3
4
5
6
7
8
一層複雜度:O(n)
1 | 7 | 5 | 6 | 2 | 3 | 8 | 4 |
---|
1 | 7 | 5 | 6 |
---|
2 | 3 | 8 | 4 |
---|
1 | 7 |
---|
5 | 6 |
---|
2 | 3 |
---|
8 | 4 |
---|
1
7
5
6
2
3
8
4
跟前面那張 "分"治 be like 那張一模一樣
1
7
5
6
2
3
8
4
1 | 7 |
---|
5 | 6 |
---|
2 | 3 |
---|
4 | 8 |
---|
1 | 5 | 6 | 7 |
---|
2 | 3 | 4 | 8 |
---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|
做一層總共有n個數字
一層的複雜度:O(n)
共有log n層
總複雜度O(n log n)
附上講師的code
中間點一下才會出現
#include<iostream> using namespace std; const int N=1e5+30; int a[N],b[N]; void merge_sort(int l,int r){ if(l==r) return; int mid=l+(r-l)/2; merge_sort(l,mid); merge_sort(mid+1,r); for(int i=l;i<=r;i++) b[i]=a[i]; int x=l,y=mid+1,cur=l; while(x<=mid&&y<=r){ if(b[x]<=b[y]){ a[cur]=b[x]; x++; }else{ a[cur]=b[y]; y++; } cur++; } while(x<=mid){ a[cur]=b[x]; cur++,x++; } while(y<=r){ a[cur]=b[y]; cur++,y++; } return; } int main(){ int n; cin>>n; for(int i=0;i<n;i++) cin>>a[i]; merge_sort(0,n-1); for(int i=0;i<n;i++) cout<<a[i]<<" "; cout<<"\n"; }
#include<algorithm> merge(a,a+n,b,b+m,c)
把 a 陣列和 b 陣列的東西排好丟到 c 陣列
(有多筆測試資料,以 n=0 結束)
Sample input:
Sample output:
5
1 2 3 4 5
5
1 2 3 5 4
0
Case #1: 0
Case #2: 1
#include<iostream> #define int long long using namespace std; const int N=1e5+30; int a[N],b[N]; int reversed(int l,int r){ if(l==r) return 0; int mid=l+(r-l)/2,ans=0; ans+=reversed(l,mid); ans+=reversed(mid+1,r); for(int i=l;i<=r;i++) b[i]=a[i]; int x=l,y=mid+1,cur=l; while(x<=mid&&y<=r){ if(b[x]<=b[y]) a[cur++]=b[x++]; else a[cur++]=b[y++],ans+=(mid-x+1); } while(x<=mid) a[cur++]=b[x++]; while(y<=r) a[cur++]=b[y++]; return ans; } signed main(){ int n,t=0; while(cin>>n&&n){ for(int i=0;i<n;i++) cin>>a[i]; cout<<"Case #"<<++t<<": "<<reversed(0,n-1)<<"\n"; } }
這題要 long long
我不會 QQ
將一個演算法的時間函數定為T(n)表示成:
可以得知
此處距離定義:
令兩點在 (x1,y1),(x2,y2),距離2=(x2−x1)2+(y2−y1)2
O(n2) 應該不是拿來對付 n=2×105 的好工具
d1
d2
d
d=min(d1,d2)
d
答案會是 min(左,右,左右之間)
問:有沒有一種可能,全部的點都在範圍內,複雜度變回 O(n2)
可以注意到:
d
d
d
d
T(n)=2T(2n)+O(nlogn)
⇒O(nlog2n)
#include<iostream> #include<algorithm> #include<vector> #define int long long using namespace std; const int N=2e5+30; typedef pair<int,int> p; p P[N]; bool cmp(int a,int b){ return P[a].second<P[b].second; } long long DQ(int l,int r){ if(l==r) return 8e18; int mid=l+(r-l)/2,cur=min(DQ(l,mid),DQ(mid+1,r)); vector<int> V; for(int i=l;i<=r;i++) if(abs(P[i].first-P[mid].first)*abs(P[i].first-P[mid].first)<cur) V.push_back(i); sort(V.begin(),V.end(),cmp); for(int i=0;i<V.size();i++){ for(int j=max(0LL,i-10);j<i;j++){ int x=(P[V[i]].first-P[V[j]].first),y=(P[V[i]].second-P[V[j]].second); if(cur>x*x+y*y) cur=x*x+y*y; } } return cur; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); int n; cin>>n; for(int i=0;i<n;i++) cin>>P[i].first>>P[i].second; sort(P,P+n); cout<<DQ(0,n-1)<<"\n"; }
#include<iostream> #include<algorithm> #include<vector> #define int long long using namespace std; const int N=2e5+30; typedef pair<int,int> p; p P[N]; bool cmp(p a,p b){ return a.second<b.second; } long long DQ(int l,int r){ if(l==r) return 8e18; int mid=l+(r-l)/2,midx=P[mid].first,cur=min(DQ(l,mid),DQ(mid+1,r)); vector<p> W(r-l+5); merge(P+l,P+mid+1,P+mid+1,P+r+1,W.begin(),cmp); for(int i=l;i<=r;i++) P[i]=W[i-l]; vector<int> V; for(int i=l;i<=r;i++) if(abs(P[i].first-midx)*abs(P[i].first-midx)<cur) V.push_back(i); for(int i=0;i<V.size();i++){ for(int j=max(0LL,i-10);j<i;j++){ int x=(P[V[i]].first-P[V[j]].first),y=(P[V[i]].second-P[V[j]].second); cur=min(cur,x*x+y*y); } } return cur; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); int n; cin>>n; for(int i=0;i<n;i++) cin>>P[i].first>>P[i].second; sort(P,P+n); cout<<DQ(0,n-1)<<"\n"; }
小數型態,有誤差
#include<iostream> using namespace std; int main(){ int a,k,ans=1; cin>>n>>k; for(int i=0;i<k;i++) n*=a; cout<<ans<<"\n"; }
複雜度: O(n)
有點慢
⇒O(logn)
最壞的狀況:偶數砍半後都是奇數,做 2× log n 次
複雜度:O(log n)
以下提供兩種做法,請點空白處
#include<iostream> using namespace std; int way1(int a,int k){ if(k==0) return 1; if(k%2) return a*way1(a,k-1); int SQRT=way1(a,k/2); return SQRT*SQRT; } int way2(int a,int k){ int ans=1,cur=a; while(k){ if(k%2==1) ans*=cur; cur*=cur; k/=2; } return ans; } int main(){ int a,k; cin>>a>>k; cout<<way1(a,k)<<" "<<way2(a,k)<<"\n"; }
題目會要求和特定數取模要注意
#include<iostream> #define int long long using namespace std; const int M=1e9+7; int dnc(int a,int k){ if(k==0) return 1; if(k%2) return (a*dnc(a,k-1)%M); int SQRT=dnc(a,k/2); return (SQRT*SQRT)%M; } signed main(){ int t,a,k; cin>>t; while(t--){ cin>>a>>k; cout<<dnc(a,k)<<"\n"; } }
(之後dp優化會再提到)
5 | 6 |
---|---|
7 | 8 |
1 | 2 |
---|---|
3 | 4 |
B矩陣
19 | 22 |
---|---|
43 | 50 |
A矩陣
注意:A 矩陣的 column 數要等於 B 矩陣的 row 數
1×5+2×7
1×6+2×8
3×5+4×7
3×6+4×8
a | b | c |
---|---|---|
d | e | f |
g | h | i |
1 | 0 | 0 |
---|---|---|
0 | 1 | 0 |
0 | 0 | 1 |
a | b | c |
---|---|---|
d | e | f |
g | h | i |
#include<iostream> using namespace std; long long squ[2][2],cur[2][2]={{1,0},{0,1}}; long long MOD(long long x){ long long M=1e9+7; return (x%M+M)%M; } void POW(int x){ long long NEW[2][2],now=x; while(now){ if(now%2){ NEW[0][0]=MOD(MOD(cur[0][0]*squ[0][0])+MOD(cur[0][1]*squ[1][0])); NEW[0][1]=MOD(MOD(cur[0][0]*squ[0][1])+MOD(cur[0][1]*squ[1][1])); NEW[1][0]=MOD(MOD(cur[1][0]*squ[0][0])+MOD(cur[1][1]*squ[1][0])); NEW[1][1]=MOD(MOD(cur[1][0]*squ[0][1])+MOD(cur[1][1]*squ[1][1])); cur[0][0]=NEW[0][0],cur[0][1]=NEW[0][1],cur[1][0]=NEW[1][0],cur[1][1]=NEW[1][1]; } NEW[0][0]=MOD(MOD(squ[0][0]*squ[0][0])+MOD(squ[0][1]*squ[1][0])); NEW[0][1]=MOD(MOD(squ[0][0]*squ[0][1])+MOD(squ[0][1]*squ[1][1])); NEW[1][0]=MOD(MOD(squ[1][0]*squ[0][0])+MOD(squ[1][1]*squ[1][0])); NEW[1][1]=MOD(MOD(squ[1][0]*squ[0][1])+MOD(squ[1][1]*squ[1][1])); squ[0][0]=NEW[0][0],squ[0][1]=NEW[0][1],squ[1][0]=NEW[1][0],squ[1][1]=NEW[1][1]; now/=2; } } int main(){ long long x1,x2,a,b,n; cin>>x1>>x2>>a>>b>>n; squ[0][0]=b,squ[0][1]=a,squ[1][0]=1,squ[1][1]=0; if(n==1) cout<<x1<<"\n"; else if(n==2) cout<<x2<<"\n"; else{ POW(n-2); cout<<MOD(MOD(cur[0][0]*x2)+MOD(cur[0][1]*x1))<<"\n"; } }