為什麼現在我題解一堆仙人掌啊
loj首先考慮樹的情況,對於樹考慮設\(f_\)表示\(u\)子樹內,\(u\)這個節點的父親邊是向上還是向下.
因為向下一定可以,向上要考慮\(a_u\),所以對於葉子節點有\(f_=1,f_=[a_u>0]\)
對於非葉子節點,你考慮怎麼轉移:
\[f_=\sum_\ \ \ \prod_f_
\]這個東西等於說是對於每乙個\(f_u\)做乙個生成函式然後卷在一起,這個可以方便的用分治\(fft\)維護.
考慮先把圓方樹建出來,我們對於狀態的定義擴充套件一下:
然後父子關係有如下三種情況:
**寫的比較長
#include#include#include#include#include#include#include#include#includeusing namespace std;
#define mp make_pair
#define ll long long
#define re register
typedef pairpii;
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi()
while(ch>='0'&&ch<='9')
return f*sum;
}const int n=200010,m=400010,mod=998244353,gg=3;
int f[n][3],a[n],n,m;
int low[n],dfn[n],time,fa[n],front[n],cnt,tot,front[n],cnt=1;
struct nodee[n<<2],e[n<<2];
void add(int u,int v);front[u]=cnt;}
void add(int u,int v);front[u]=cnt;}
int stk[n],tp;
void tarjan(int u,int ff)
while(stk[tp--]!=v);
}else if(dfn[u]>=1;a=1ll*a*a%mod;}return ret;}
void ntt(int *a,int limit,int opt)
void dfs(int u,int ff)
int son=0;
for(int i=front[u];i;i=e[i].nxt)
vectorb=cdq(1,son);b.resize(a[u]+1);
for(int i=1;i<=a[u];i++)b[i]=(b[i]+b[i-1])%mod;
if(~a[u])f[u][0]=b[a[u]];
if(a[u])f[u][1]=b[a[u]-1];
if(a[u]>1)f[u][2]=b[a[u]-2];
} else
f[u][j]=(f[u][j]+s1)%mod;f[u][j+1]=(f[u][j+1]+s0)%mod;
} }}int main()
for(int i=1;i<=n;i++)a[i]=gi();
tarjan(1,0);
dfs(1,0);
printf("%d\n",f[1][0]);
return 0;
}
雅禮集訓 2018 Day4 Magic
傳送門本部分 於 這位大佬 題中要求本質不同的序列數量,不太好搞。我們考慮給相同顏色的牌加上編號,這樣所有牌都不相同。那麼如果我們求出了答案,只需要將答案除以 prod a i 就好了。恰好有 k 對 不能直接求,考慮容斥,如果我們求出了 g x 表示至少有 x 對的方案數,那麼答案即為 sum l...
雅禮集訓 2018 Day7 A 題解
題意 雅禮集訓 2018 day7 a 題解 線段樹處理。考慮只有一種與的操作。顯然當乙個區間的或和與上將要與的數還是原數時就沒必要遞迴計算了,剪枝剪掉。當一段區間與和與上將要與的數等於這段區間或和與上將要與的數時,更新後這段區間的最小值位置還是更新前的位置。由於一次操作至少將數的乙個二進位制改變,...
雅禮集訓 2018 Day10 貪玩藍月
點這裡看題目。離線的話,我們顯然可以 線段樹分治 dp 時間複雜度大概是 o m log 2m mp 顯然我們需要乙個 dp 去維護答案,這裡不再贅述。考慮我們直接處理的難點之一是雙端佇列兩段可操作,而一端可操作的結構,棧,就可以簡單地維護 dp 因此,我們考慮將雙端佇列拆成兩棧分別維護左端和右端。...