洛谷4755 Beautiful Pair (分治)
題目描述
小D有個數列 \(a\),當一個數對 \((i,j)(i\le j)\) 滿足\(a_i\)和\(a_j\)的積 不大於 \(a_i \cdots a_j\) 中的最大值時,小D認為這個數對是美麗的.請你求出美麗的數對的數量。
輸入格式:
第一行輸入一個整數 \(n\),表示元素個數。 第二行輸入 \(n\) 個整數 \(a_1,a_2,a_3,\cdots,a\),為所給的數列。
輸出格式:
輸出一個整數,為美麗的數字對數。
其中\(m\le 10^5,a_i \le 10^9\)
這個題,看到題的第一想法就是QwQ,一看就是dp或者一些惡心的數據結構題,但是想了一會dp,發現不太可行。那麽我們可以考慮通過分治
我們考慮,對於一個區間\([l,r]\),我們可以通過這個區間的\(mx\)(表示最大的\(a_i\))來解決,因為要求乘積不能大於區間的最大值,所以我們在 計算區間的時候,\(mx\)一般情況下是不能和別的數進行組合的。所以說,按照mx來分組,那麽當前區間的答案就是\([l,mx-1]\)的答案加上\([mx+1,r]\),然後加上兩個區間產生的貢獻。
QwQ那麽怎麽求左右區間產生的貢獻呢
我們考慮,對於一個固定的左端點\(l\),我們需要在\([mx+1,r]\)區間找出,小於\(\lfloor \frac{mx}{a_l} \rfloor\)的數的個數
然後我們枚舉所有的左端點,然後數一數,最後考慮\(mx\)
那麽我們應該怎麽求一個區間內小於等於一個數的個數呢
QwQ
呀,BIT!樹狀數組 嗯!
我們考慮將每個數進行離散化,然後維護一個權值樹狀數組,然後我們每次只需要\(query(find(\lfloor \frac{mx}{a_l} \rfloor))\)就可以,其中\(find\)的函數的作用是,找到這個值離散化後的小於等於它的最大的值,其實可以直接\(lower_bound\)
記得離散化!
還有一些人會問,這個算法的時間復雜度可以保證嗎?QwQ具體的證明我也不是很會呀,不過可以感性l理解
如果我們每次挑選的\(mx\),都選擇比較中間的,那麽我們可以大致理解是\(O(nlogn)\)
直接上代碼
dfs版的分治
非常理解,個人敢接
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<unordered_map>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch==‘-‘) f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
return x*f;
}
const int maxn = 1e5+1e2;
int c[maxn];
int a[maxn];
int b[maxn];
int n,m;
int dp[maxn][23];
int p[maxn];
int tmp = 0;
unordered_map<int,int> mp;
struct Node{
int id,val;
};
Node g[maxn];
int lowbit(int x)
{
return (-x) & x;
}
void update(int x,int p)
{
for (int i=x;i<=n;i+=lowbit(i)) c[i]+=p;
}
long long query(int x)
{
long long ans=0;
for (int i=x;i;i-=lowbit(i)) ans+=(long long)c[i];
return ans;
}
int find(int x)
{
if (x>p[n]) return tmp;
return g[upper_bound(p+1,p+1+n,x)-p-1].id;
}
bool cmp(Node a,Node b)
{
return a.val<b.val;
}
int countmax(int x,int y)
{
int k = log2(y-x+1);
return max(dp[x][k],dp[y-(1 <<k)+1][k]);
}
void init()
{
for (int j=1;j<=21;j++)
for (int i=1;i<=n;i++)
{
if (i+(1 << j)-1<=n)
{
dp[i][j]=max(dp[i][j-1],dp[i+(1 << (j-1))][j-1]);
}
}
}
long long solve(int l,int r)
{
if (l>r) return 0;
if (l==r) {
if (a[l]==1)return 1;
else return 0;
}
long long cnt=0;
int mid = (l+r) >> 1;
int mx = countmax(l,r),pos=0;
for (int i=l;i<=r;i++)
{
if (a[i]==mx) {
if (!pos || abs(mid-i)<abs(mid-pos)) pos=i;
}
}
cnt+=solve(l,pos-1);
cnt+=solve(pos+1,r);
for (int i=pos+1;i<=r;i++) update(b[i],1);
for (int i=l;i<=pos;i++) cnt=cnt+(query(find(mx/a[i])));
for (int i=pos+1;i<=r;i++) update(b[i],-1);
//cout<<l<<" "<<r<<" "<<cnt<<endl;
for (int i=l;i<=pos-1;i++) update(b[i],1);
cnt=cnt+(query(find(mx/a[pos])));
for (int i=l;i<=pos-1;i++) update(b[i],-1);
//out<<l<<" "<<r<<" "<<cnt<<endl;
if (a[pos]==1) cnt++;
return cnt;
}
int main()
{
n=read();
for (int i=1;i<=n;i++) a[i]=read(),g[i].id=i,g[i].val=a[i],dp[i][0]=a[i];
init();
sort(g+1,g+1+n,cmp);
for (int i=1;i<=n;i++)
{
if (g[i].val!=g[i-1].val) tmp++;
b[g[i].id]=tmp;
mp[a[g[i].id]]=tmp;
}
//for (int i=1;i<=n;i++) cout<<b[i]<<" ";
memset(g,0,sizeof(g));
for (int i=1;i<=n;i++) p[i]=a[i],g[i].val=a[i],g[i].id=b[i];
sort(g+1,g+1+n,cmp);
sort(p+1,p+1+n);
//cout<<endl;
long long ans=solve(1,n);
cout<<ans;
return 0;
}
洛谷4755 Beautiful Pair (分治)