你相信引力嗎?(一道單調棧的題)
阿新 • • 發佈:2018-12-18
這道題我想了很久,沒想出來。
首先我們要把這個環,找一個斷點,給斷成序列。
當然是從最大的點斷開是最好的,不會有兩個點(i,j),如下圖,藍色一段是不可能使(i,j)危險的,因為i,j 小於最大值。
使i,j成為危險的只有可能i到j中沒有嚴格大於i和j的。
這樣,我們先不考慮第一個點為右端點的情況,正著跑一遍單調棧(單調遞減),
假設i要進棧,如果棧頂小於i ,那麼彈棧,i和棧頂會產生1的貢獻。
如果i == 棧頂,那麼i會和所有與棧頂的值相同的元素都產生1的貢獻。
同時會和棧中大於棧頂的第一個元素產生1的貢獻。
然後i進棧。
棧單調遞減,同時維護相同元素的個數。
然後我們要處理的就是以第一個點作為右端點的滿足條件的點對。(有兩種方法)
第一:
假設左端點為i ,也就是說從i到末尾沒有一個元素嚴格大於i。
倒著for一遍就好。
但是注意,如果遇到次大值就break了。。。。(因為正著單調棧的時候,已經算過最大值和次大值的貢獻了。而對於次大值後面的數,如果它大於所有它後面的數顯然是可以和第一個點組成危險冰錐的)
第二:
如果是以第一個點作為右端點的滿足條件的點對,那麼肯定不能和第一次正著for的時候有重疊=。=
對於冰錐i,它一定是i-n裡最高的,但一定不是1-i裡最高的。
統計這樣的冰錐數就好。
//有兩份程式碼,第一份是我的(單調棧寫的比較醜,有點慢,用了離散化,找以第一個點作為右端點的滿足條件的點對時用的第一種方法),第二份是同學的(找以第一個點作為右端點的滿足條件的點對時用的第二種方法)。
#include<bits/stdc++.h> using namespace std; int n, vis[5000005], a[5000005] ,ma, wcma, wma, cma ,b[5000005], zhan[5000005], top, tp, len[5000005], cnt, sval[5000005], ans; int main() { scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); if(a[i] > ma) { ma = a[i]; wma = i; } } for(int i = wma; i <= n; i++) { b[++cnt] = a[i]; sval[cnt] = a[i]; } for(int i = 1; i < wma;i++) { b[++cnt] = a[i]; sval[cnt] = a[i]; } sort(sval+1,sval+1+n); cma = sval[n-1]; int m = unique(sval+1,sval+1+n) - sval - 1; for(int i = 1; i <= cnt; i++) { b[i] = lower_bound(sval+1,sval+1+m,b[i]) - sval; } cma = lower_bound(sval+1,sval+1+m,cma) - sval; zhan[++top] = b[1]; vis[b[1]]++; for(int i = 2; i <= cnt; i++) { while(top && (zhan[top] < b[i])) { ans ++; vis[zhan[top]]--; top--; } if(zhan[top] == b[i] && top) { ans += vis[zhan[top]]; if(top - vis[zhan[top]] > 0) ans ++; vis[zhan[top]]++; zhan[++top] = b[i]; } else { if(top)ans++; zhan[++top] = b[i]; vis[b[i]]++; } } int ha = 0; for(int i = n; i >=2; i--) { if(b[i] == cma) break; if(b[i] >= ha) { ans++; ha = b[i];} } cout << ans; return 0; }
#include<bits/stdc++.h>
using namespace std;
const int N = 5000005;
int n, a[N] ,ma, wma, b[N], top, cma[N], tp, len[N], cnt, sval[N], ans, tmp[N], lma[N], rma[N];
struct node {
int size, val;
node(int val = 0, int size = 0): size(size), val(val) {}
}zhan[N];
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
if(a[i] > ma)
{
ma = a[i];
wma = i;
}
}
for(int i = wma; i <= n; i++)
{
b[++cnt] = a[i];
}
for(int i = 1; i < wma;i++)
{
b[++cnt] = a[i];
}
for(int i = 2;i <= n;i ++) {
if(b[i] >= tmp[i - 1]) lma[i] = 1, tmp[i] = b[i];
else tmp[i] = max(tmp[i], tmp[i - 1]);
} memset(tmp, 0, sizeof(tmp));
for(int i = n;i >= 1;i --) {
if(b[i] >= tmp[i + 1]) rma[i] = n, tmp[i] = b[i];
else tmp[i] = max(tmp[i], tmp[i + 1]);
}
zhan[++top] = node(b[1], 1);
for(int i = 2; i <= n; i++)
{
while(zhan[top].val < b[i] && top)
{
ans += zhan[top].size;
top--;
}
if(b[i] == zhan[top].val) {
ans += zhan[top].size; zhan[top].size ++;
if(top > 1) ans ++; continue;
}
if(top) ans ++;
zhan[++top] = node(b[i], 1);
}
int tp = 0;
for(int i = 2;i <= n;i ++) if(lma[i] != 1 && rma[i] == n) ans ++;
cout << ans;
return 0;
}