Vijos p1892 树上的最大匹配 树形DP+计数 被卡常我有特殊技巧heheda

https://vijos.org/p/1892

此题需要手动开栈:

int size=256<<20; //256MB
char *p=(char*)malloc(size)+size;
__asm__("movl %0, %%esp\n" :: "r"(p));

还需要卡评测机←十分的神

 卡了30多次评测机终于屈服了,一开始我盲目乱提交,总是T,后来上网找了一下解决卡常数方法,如下:

  解决卡常数的方法比较多样化,主要有重复交题,拼人品让测评机快一点,在代码末尾加上//orz+神犇名字等(注意:没加“//”可能导致运行时间直接变为0ms!)。很多计算机算法竞赛的专家也在钻研如何解决这一问题,所以类似ZKW线段树等可以有效减少常数的时间占用的方法也在不断被发现,今后还有很大的探索空间。


没错,从那之后我提交就在程序最后加// orz ...,把人差不多都%了个遍,但都是90分,%charge时只是80分,但当我%马神(Godder)时成功AC!所以以后被卡常时就%%Godder,说不定就能AC。OI隐藏技能

以下是我的ACcode,重点在倒数第二行,保我AC的那一行

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
inline const int max(const int &a,const int &b){return a>b?a:b;}
inline const int min(const int &a,const int &b){return a<b?a:b;}
const int N=2000005;
struct charge{
    int nxt,to;
}e[N<<1];
int cnt=0,point[N],r[N],sr[N],et[N],f[N][2];
long long M,g[N][2];
void read(int &sum)
{
    char c=getchar();sum=0;
    while (c<'0'||c>'9') c=getchar();
    while ('0'<=c&&c<='9') sum=sum*10+c-48,c=getchar();
}
void insect(int x,int y){e[++cnt].nxt=point[x];point[x]=cnt;e[cnt].to=y;}
void dp(int x,int fa)
{
    long long tp; int mx,j,sz=0;
    g[x][0]=1;
    for (int i=point[x];i;i=e[i].nxt) if (e[i].to!=fa)
    {
        j=e[i].to;
        dp(j,x); tp=0;
        mx=max(f[j][0],f[j][1]); f[x][0]+=mx;
        if (f[j][0]==mx) tp=g[j][0];
        if (f[j][1]==mx) tp+=g[j][1];
        g[x][0]=(g[x][0]*tp)%M;
    }
    for (int i=point[x];i;i=e[i].nxt)
     if (e[i].to!=fa) et[++sz]=e[i].to;
    r[sz+1]=0; sr[sz+1]=1;
    for3 (i,sz,1)
    {
        mx=max(f[et[i]][0],f[et[i]][1]);
        r[i]=r[i+1]+mx;
        tp=0;
        if (f[et[i]][0]==mx) tp=g[et[i]][0];
        if (f[et[i]][1]==mx) tp+=g[et[i]][1];
        sr[i]=(sr[i+1]*tp)%M;
    }
    long long sl=1; int l=0;
    for1 (i,1,sz)
    {
        mx=l+r[i+1]+f[et[i]][0]+1;
        if (mx>f[x][1])
        {
            f[x][1]=mx;
            g[x][1]=((sl*sr[i+1])%M*g[et[i]][0])%M;
        }
        else if (mx==f[x][1])
              g[x][1]=(g[x][1]+(((sl*sr[i+1])%M*g[et[i]][0])%M))%M;
        mx=max(f[et[i]][0],f[et[i]][1]);
        l+=mx; tp=0;
        if (f[et[i]][0]==mx) tp=g[et[i]][0];
        if (f[et[i]][1]==mx) tp+=g[et[i]][1];
        sl=(sl*tp)%M;
    }
}
void outit()
{
    int mx=max(f[1][0],f[1][1]),ans=0;
    if (mx==f[1][0]) ans=g[1][0];
    if (mx==f[1][1]) ans+=g[1][1];
    printf("%d\n%lld\n",mx,ans%M);
}
int main()
{
    int size=256<<20; //256MB
    char *p=(char*)malloc(size)+size;
    __asm__("movl %0, %%esp\n" :: "r"(p));
    memset(point,0,sizeof(point));
    memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));
    int n,i,x,y;
    read(n);
    for2 (i,1,n)
    {
        read(x); read(y);
        insect(x,y); insect(y,x);
    }
    scanf("%lld\n",&M);
    dp(1,-1);
    outit();
    return 0;
    // orz Godder
}

然后就行了。

你可能感兴趣的:(Vijos p1892 树上的最大匹配 树形DP+计数 被卡常我有特殊技巧heheda)