bzoj4881 線段遊戲

2021-08-01 09:01:24 字數 1657 閱讀 1631

相當於走出兩條路線,將所有數包含,使得每條路線都是單調增的。

為了方便我們加入p[0]=0和p[n+1]=n+1。

設f[i]表示一條路線(沒有指定是第一條路線)走到了i-1,另一條路線走到了i,滿足條件的方案數。

邊界是f[1]=1,答案是f[n+1]*2(兩條路線實際上不可區分但原題中可區分那麼它們可以交換即乘2)。

如何轉移呢?在i的路線會包含一段區間[i,j],而不包含j+1,則j+1被處在i-1的路線包含,然後就可以轉移到f[j+1]。

需要滿足的條件是[i,j]單增,p[

i−1]

j+1]

。 可以預處理next[i]表示最大的j滿足[i,j]單增,next陣列有單調性。

那麼這就是暴力dp了。

我們按順序掃。

當我們做出f[i]後,接下來可以轉移到的j必須滿足p[

j+1]

>p[

i−1]

j<=ne

xt[i

]

#include

#include

#define fo(i,a,b) for(i=a;i<=b;i++)

#define fd(i,a,b) for(i=a;i>=b;i--)

using namespace std;

const int maxn=100000+10,mo=998244353;

int ad[maxn*4];

int h[maxn],go[maxn],nxt[maxn];

int ask[maxn][3];

int id[maxn],a[maxn],next[maxn],f[maxn];

int i,j,k,l,t,n,m,tot,top;

intread()

while (ch>='0'&&ch<='9')

return

x*f;

}void add(int

x,int

y)void mark(int p,int v)

void down(int p)

}void change(int p,int l,int r,int a,int b,int v)

down(p);

int mid=(l+r)/2;

if (b<=mid) change(p*2,l,mid,a,b,v);

else

if (a>mid) change(p*2+1,mid+1,r,a,b,v);

else

}int query(int p,int l,int r,int a)

int main()

f[1]=1;

fo(i,1,n+1)

if (i>1) f[i]=query(1,0,n+1,a[i]);

if (i>n) break;

top++;

ask[top][0]=a[i-1]+1;

ask[top][1]=n+1;

ask[top][2]=f[i];

add(next[i]+2,top);

change(1,0,n+1,a[i-1]+1,n+1,f[i]);

}(f[n+1]+=mo)%=mo;

printf("%d\n",f[n+1]*2

%mo);

}

bzoj 4515 遊戲 樹鏈剖分 線段樹

先讓我 一發lych大佬點我去看dalao的題解 講的很詳細.這裡糾正乙個地方,lych大佬的式子中有乙個 a d s d x b a d x b a d s 應該是 a d s d x b a d x b a d s 看來是大爺敲式子的時候敲錯了.除去這個就很完美啦 新get了線段樹標記永久化的姿...

BZOJ5005 桌球遊戲 線段樹 並查集

如果乙個區間的端點在區間內,則這個區間可以走到那個區間,詢問乙個區間能否到另乙個區間。首先我們立馬想到了 如果兩個區間嚴格有交集,那麼這兩個區間所能到達的區間集合是一樣的。那麼如果兩個區間嚴格有交集的話我們就可以把它們合併起來,這裡運用並查集。這樣處理完之後,剩下的區間只有兩種情況 包含或者相離。那...

BZOJ 4756 線段樹合併(線段樹)

思路 1.最裸的線段樹合併 2.我們可以觀察到子樹求乙個東西 那我們直接dfs序好了 入隊的時候統計一下有多少比他大的 出的時候統計一下 減一下 搞定 線段樹合併 by siriusren include include include using namespace std const int n...