1. 程式人生 > >BZOJ5123 線段樹的匹配(樹形dp)

BZOJ5123 線段樹的匹配(樹形dp)

  線段樹的任意一棵子樹都相當於節點數與該子樹相同的線段樹。於是假裝在樹形dp即可,記憶化搜尋實現,有效狀態數是logn級別的。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
#define P 998244353
char
getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while
(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } ll n; map<ll,ll> f[2],g[2]; void solve(ll n) { if (g[0].find(n)!=g[0].end()) return; ll lson=n+1>>1,rson=n-lson; solve(lson),solve(rson); f[0][n]=max(f[0][lson],f[1][lson])+max(f[0
][rson],f[1][rson]); f[1][n]=max(f[0][lson]+max(f[0][rson],f[1][rson]),f[0][rson]+max(f[0][lson],f[1][lson]))+1; ll x=f[0][lson]==f[1][lson]?g[0][lson]+g[1][lson]:(f[0][lson]>f[1][lson]?g[0][lson]:g[1][lson]); ll y=f[0][rson]==f[1][rson]?g[0][rson]+g[1][rson]:(f[0][rson]>f[1][rson]?g[0][rson]:g[1][rson]); g[0][n]=x*y%P; if (f[0][lson]+max(f[0][rson],f[1][rson])==f[0][rson]+max(f[0][lson],f[1][lson])) g[1][n]=(g[0][lson]*y+x*g[0][rson])%P; else if (f[0][lson]+max(f[0][rson],f[1][rson])>f[0][rson]+max(f[0][lson],f[1][lson])) g[1][n]=g[0][lson]*y%P; else g[1][n]=x*g[0][rson]%P; return; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5123.in","r",stdin); freopen("bzoj5123.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif cin>>n;f[0][1]=0,f[1][1]=-n,g[0][1]=1,g[1][1]=0; solve(n); if (f[0][n]==f[1][n]) cout<<f[0][n]<<' '<<(g[0][n]+g[1][n])%P; else if (f[0][n]>f[1][n]) cout<<f[0][n]<<' '<<g[0][n]; else cout<<f[1][n]<<' '<<g[1][n]; return 0; }