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;
}

猜你喜欢

转载自www.cnblogs.com/Gloid/p/10089009.html