您的位置:首页 > 其它

bzoj千题计划164:bzoj5123: 线段树的匹配

2017-12-30 09:46 309 查看
http://www.lydsy.com/JudgeOnline/upload/201712/prob12.pdf

dp[len][0/1] 表示节点表示区间长度为len,节点选/不选的 最大匹配

sum[len][0/1] 表示对应dp[len][0/1]的方案数

这里选节点即选节点与其父节点的边

设区间长度为len,左子区间长度为L,右子区间长度为R

这个节点选,那么左右子节点都不能选

dp[len][1]=1+dp[L][0]+dp[R][0]

sum[len][1]=sum[L][0]*sum[R][0]

这个节点不选,有3种情况:

左右子节点都不选:

dp[len][0]=dp[L][0]+dp[R][0]

sum[len][0]=sum[L][0]+sum[R][0]

选左子节点:

dp[len][0]=dp[L][1]+dp[R][0]

sum[len][0]=sum[L][1]+sum[R][0]

选右子节点:

dp[len][0]=dp[L][0]+dp[R][1]

sum[len][0]=sum[L][0]+sum[R][1]

如果dp[len][0] 在三种情况中有相同的,sum[len][0]要累加

len虽然是1e18,但只会用log种,所以用map

#include<map>
#include<cstdio>
#include<cstring>

using namespace std;

typedef long long LL;

const int mod=998244353;

//int dp[100001][2];
//int sum[10001][2];

map<LL,LL>dp[2];
map<LL,LL>sum[2];

void dfs(LL len)
{
if(len==1)
{
dp[0][1]=0;
sum[0][1]=1;
dp[1][1]=1;
sum[1][1]=1;
return;
}
LL R=len>>1;
LL L=len-R;
if(dp[0].find(L)==dp[0].end()) dfs(L);
if(dp[0].find(R)==dp[0].end()) dfs(R);
dp[1][len]=1+dp[0][L]+dp[0][R];
sum[1][len]=sum[0][L]*sum[0][R]%mod;
dp[0][len]=dp[1][len]-1;
sum[0][len]=sum[1][len];
if(dp[0][L]+dp[1][R]>dp[0][len])
{
dp[0][len]=dp[0][L]+dp[1][R];
sum[0][len]=sum[0][L]*sum[1][R]%mod;
}
else if(dp[0][L]+dp[1][R]==dp[0][len])
{
sum[0][len]=(sum[0][len]+sum[0][L]*sum[1][R])%mod;
}
if(dp[1][L]+dp[0][R]>dp[0][len])
{
dp[0][len]=dp[1][L]+dp[0][R];
sum[0][len]=sum[1][L]*sum[0][R]%mod;
}
else if(dp[1][L]+dp[0][R]==dp[0][len])
{
sum[0][len]=(sum[0][len]+sum[1][L]*sum[0][R])%mod;
}
}

int main()
{
LL n;
scanf("%I64d",&n);
dfs(n);
printf("%I64d %I64d",dp[0]
,sum[0]
);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: