# 匹配 解题报告

521人阅读 评论(0)

n1.5106,m109

= =这是一道卡内存傻题，一个显然的DP方程是设f(n,0/1)为这个点向其父亲的边选或不选这个子树能得到的最大匹配，然后g(n,0/1)是其方案数，然后随便转移一下就好了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<bitset>
using namespace std;
bitset<1500005> flag;
int succ[3000005],ptr[1500005],next[3000005],etot=1;
void in(int &x){
char c=getchar();
while(c<'0'||c>'9')c=getchar();
x=0;
for(;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');
}
next[etot]=ptr[u],ptr[u]=etot,succ[etot++]=v;
}

int m,n;
//next[1..n]表示i的儿子们在哪里开始的，succ[1..n]存它的儿子们,ptr[1..n]存它的父亲们。
//next[n+1+1..n+1+n]表示其儿子们的最大深度,succ[n+1..n+n]存每个点的depth
struct DS{
int f[2],g[2];
};
typedef long long LL;
#define inf 1000000000
DS dfs(int node,int depth){
int i,Maxson;
while(next[node]!=next[node+1]){
succ[n+node]=depth;
Maxson=succ[next[node]];
for(i=next[node];++i<next[node+1];)
if(next[n+1+succ[i]]>next[n+1+Maxson])
Maxson=succ[i];
node=Maxson;
}
succ[n+node]=depth;
DS ans,sps,Max,now;
for(;;){
ans=(DS){{0,1},{1%m,1%m}},Max=(DS){{inf,-inf},{1%m,1%m}};
for(i=next[node];i<next[node+1];++i){
if(succ[n+succ[i]])now=sps;
else now=dfs(succ[i],depth+1);
if(now.f[1]-now.f[0]>Max.f[1]-Max.f[0]){
Max=now;
Max.g[0]=(LL)ans.g[1]*now.g[1]%m;
if(now.f[1]-now.f[0]==0)Max.g[0]=(Max.g[0]+(LL)ans.g[1]*now.g[0])%m;
}
else
if(now.f[1]-now.f[0]==Max.f[1]-Max.f[0])Max.g[0]=((LL)Max.g[0]*now.g[0]+(LL)ans.g[1]*now.g[1])%m;
else Max.g[0]=(LL)Max.g[0]*now.g[0]%m;
ans.f[1]+=now.f[0];
ans.g[1]=(LL)ans.g[1]*now.g[0]%m;
}
if(Max.f[1]-Max.f[0]>=0){
ans.g[0]=Max.g[0];
ans.f[0]=ans.f[1]-1+Max.f[1]-Max.f[0];
}
else{
ans.g[0]=ans.g[1];
ans.f[0]=ans.f[1]-1;
}
sps=ans;
//cout<<node<<":"<<ans.f[0]<<","<<ans.f[1]<<" "<<ans.g[0]<<","<<ans.g[1]<<endl;
if(succ[n+ptr[node]]==succ[n+node])node=ptr[node];
else return ans;
}
}
int main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
int i,u,v,j;
in(n);
for(i=n;--i;){
in(u),in(v);
}
in(m);
//dfs出父亲来。
int node=1,tmp;
flag[1]=1;
while(node){
if(!flag[succ[ptr[node]]]){
flag[succ[ptr[node]]]=1;
tmp=node;
node=succ[ptr[node]];
ptr[tmp]=next[ptr[tmp]];
}
else if(next[ptr[node]])swap(succ[ptr[node]],succ[next[ptr[node]]]);
else{
ptr[node]=succ[ptr[node]];
node=ptr[node];
}
}
//按父亲排序
//next[n+2..n+n]作为新next，succ[n+1..n]作为新的表头。
//ptr[1..n]是父亲,next[1..n]作为分界点。
memset(succ,0,sizeof(succ));
memset(next,0,sizeof(next));
for(i=1;i<=n;++i)next[i+n]=succ[n+ptr[i]],succ[n+ptr[i]]=n+i;
next[1]=1;
for(i=1;i<=n;++i){
next[i+1]=next[i];
for(j=succ[n+i];j;j=next[j])succ[next[i+1]++]=j-n;
}
for(i=1;i<=n;++i)next[n+2+i]=0;
//求最大深度
flag.reset();
for(i=n;i;--i)succ[n+i]=next[i];
node=1;
while(node){
if(succ[n+node]==next[node+1]){
++next[n+1+node];
flag[node]=1;
node=ptr[node];
}
else
if(!flag[succ[succ[n+node]]])node=succ[succ[n+node]];
else next[n+1+node]=max(next[n+1+node],next[n+1+succ[succ[n+node]++]]);
}
for(i=n;i;--i)succ[n+i]=0;
//dp
DS ans=dfs(1,1);
printf("%d\n%d\n",ans.f[0],ans.g[0]);
}

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<iostream>
#include<bitset>
using namespace std;
bool flag[1500005];
int succ[3000005],ptr[1500005],next[3000005],etot=1;
void in(int &x){
char c=getchar();
while(c<'0'||c>'9')c=getchar();
x=0;
for(;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');
}
next[etot]=ptr[u],ptr[u]=etot,succ[etot++]=v;
}

int m,n;
//next[1..n]表示i的儿子们在哪里开始的，succ[1..n]存它的儿子们,ptr[1..n]存它的父亲们。
//next[n+1+1..n+1+n]表示其儿子们的最大深度,succ[n+1..n+n]存每个点的depth
struct DS{
int f[2];
long long g[2];
};
#define inf 1000000000
DS dfs(int node,int depth){
int i,Maxson;
while(next[node]!=next[node+1]){
succ[n+node]=depth;
Maxson=succ[next[node]];
for(i=next[node];++i<next[node+1];)
if(next[n+1+succ[i]]>next[n+1+Maxson])
Maxson=succ[i];
node=Maxson;
}
succ[n+node]=depth;
DS ans,sps,Max,now;
for(;;){
ans=(DS){{0,1},{1%m,1%m}},Max=(DS){{inf,-inf},{1%m,1%m}};
for(i=next[node];i<next[node+1];++i){
if(succ[n+succ[i]])now=sps;
else now=dfs(succ[i],depth+1);
if(now.f[1]-now.f[0]>Max.f[1]-Max.f[0]){
Max=now;
Max.g[0]=ans.g[1]*now.g[1]%m;
if(now.f[1]-now.f[0]==0)Max.g[0]=(Max.g[0]+ans.g[1]*now.g[0])%m;
}
else
if(now.f[1]-now.f[0]==Max.f[1]-Max.f[0])Max.g[0]=(Max.g[0]*now.g[0]+ans.g[1]*now.g[1])%m;
else Max.g[0]=Max.g[0]*now.g[0]%m;
ans.f[1]+=now.f[0];
ans.g[1]=ans.g[1]*now.g[0]%m;
}
if(Max.f[1]-Max.f[0]>=0){
ans.g[0]=Max.g[0];
ans.f[0]=ans.f[1]-1+Max.f[1]-Max.f[0];
}
else{
ans.g[0]=ans.g[1];
ans.f[0]=ans.f[1]-1;
}
sps=ans;
//cout<<node<<":"<<ans.f[0]<<","<<ans.f[1]<<" "<<ans.g[0]<<","<<ans.g[1]<<endl;
if(succ[n+ptr[node]]==succ[n+node])node=ptr[node];
else return ans;
}
}
int main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
int i,u,v,j;
in(n);
for(i=n;--i;){
in(u),in(v);
}
in(m);
//dfs出父亲来。
int node=1,tmp;
flag[1]=1;
//printf("%f\n",(double)clock()/CLOCKS_PER_SEC);
while(node){
if(!flag[succ[ptr[node]]]){
flag[succ[ptr[node]]]=1;
tmp=node;
node=succ[ptr[node]];
ptr[tmp]=next[ptr[tmp]];
}
else if(next[ptr[node]])swap(succ[ptr[node]],succ[next[ptr[node]]]);
else{
ptr[node]=succ[ptr[node]];
node=ptr[node];
}
}
//printf("%f\n",(double)clock()/CLOCKS_PER_SEC);
//按父亲排序
//next[n+2..n+n]作为新next，succ[n+1..n]作为新的表头。
//ptr[1..n]是父亲,next[1..n]作为分界点。
memset(succ,0,sizeof(succ));
memset(next,0,sizeof(next));
for(i=1;i<=n;++i)next[i+n]=succ[n+ptr[i]],succ[n+ptr[i]]=n+i;
next[1]=1;
for(i=1;i<=n;++i){
next[i+1]=next[i];
for(j=succ[n+i];j;j=next[j])succ[next[i+1]++]=j-n;
}
memset(next+n+3,0,sizeof(int)*n);
//printf("%f\n",(double)clock()/CLOCKS_PER_SEC);
//求size
memset(flag,0,sizeof(flag));
for(i=n;i;--i)succ[n+i]=next[i];
node=1;
while(node){
if(succ[n+node]==next[node+1]){
++next[n+1+node];
flag[node]=1;
node=ptr[node];
}
else
if(!flag[succ[succ[n+node]]])node=succ[succ[n+node]];
else next[n+1+node]+=next[n+1+succ[succ[n+node]++]];
}
memset(succ+n+1,0,sizeof(int)*n);
//printf("%f\n",(double)clock()/CLOCKS_PER_SEC);
//dp
DS ans=dfs(1,1);
//printf("%f\n",(double)clock()/CLOCKS_PER_SEC);
printf("%d\n%I64d\n",ans.f[0],ans.g[0]);
}

①一定要试极限数据啊！！！尤其是模的数有范围的情况！
②如果不是为了位运算还是不要用bitset的好，直接布尔数组快多了。。
③不要用什么沙茶n$\sqrt n$直径分治了，被链剖log2n$log_2n$虐爆了有木有！

0
0

个人资料
• 访问：174530次
• 积分：3634
• 等级：
• 排名：第10687名
• 原创：187篇
• 转载：1篇
• 译文：0篇
• 评论：25条
最新评论