謝允恆
分而治之
切割到規模夠小時會有一定的特性能解決子問題
觀察問題的性質
將子問題的答案回推至大問題
以求出最大值為例
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)\)表示成:
可以得知
此處距離定義:
令兩點在 \((x_1,y_1),(x_2,y_2) \),\(距離^2=(x_2-x_1)^2+(y_2-y_1)^2 \)
\(O(n^2)\) 應該不是拿來對付 \(n=2\times10^5\) 的好工具
\(d_1\)
\(d_2\)
\(d\)
\(d=min(d_1, d_2)\)
\(d\)
答案會是 \(min(左, 右, 左右之間)\)
問:有沒有一種可能,全部的點都在範圍內,複雜度變回 \(O(n^2)\)
可以注意到:
\(d\)
\(d\)
\(d\)
\(d\)
\(T(n) = 2T(\frac{n}{2}) + O(n \log n)\)
\(\Rightarrow O(n \log^2 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(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)\)
有點慢
\(\Rightarrow O(\log n)\)
最壞的狀況:偶數砍半後都是奇數,做 \(2\times \ 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\times 5 + 2\times 7\)
\(1\times 6 + 2\times 8\)
\(3\times 5 + 4\times 7\)
\(3\times 6 + 4\times 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";
}
}