CSP-S2019題解

格雷碼

€€£:我不抄自己辣!JOJO!

這題比那個SCOI的炒雞格雷碼好多了,甚至告訴你構造方法,所以...

void wk(uLL kk)
{
    int j=0;
    for(uLL i=n-1;~i;--i)
    {
        if(kk>>i&1) printf("%d",j^1),j^=j==0;
        else printf("%d",j),j^=j==1;
    }
}

括號樹

考慮樸素做法,即dfs整棵樹,然後記錄到根的括號序列,每個點的貢獻爲祖先貢獻+以自己這個位置爲右端點的合法括號序列數量,可以\(O(n^2)\)

考慮優化,我們要統計的括號序列是一段後綴,所以把\()\)看做\(1\),\((\)看做\(-1\),那麼一個後綴爲合法括號序列當且僅當這一段的權值和爲0,且這個後綴沒有包含一段和\(<0\)的後綴(也就是有一些\((\)一定匹配不上),那麼線段樹每個位置維護對應後綴的和,以及再維護區間權值0個數(就是維護區間最小值以及其個數),每次進入一個點先對所有後綴\(+1/-1\),然後線段樹上二分找出權值\(<0\)的最靠右位置\(p\),那麼以這個點爲最右端的合法括號序列個數就是\([p+1,dep_x]\)內權值0個數


code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=5e5+10;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
int to[N],nt[N],hd[N],tot=1;
void add(int x,int y)
{
    ++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
}
LL f[N],ans;
char cc[N];
int n,fa[N];
int tg[N*5];
struct node
{
    int x,n;
}xzz[N*5],fkrr;
node mergg(node aa,node bb)
{
    if(aa.x<bb.x) return aa;
    else if(aa.x>bb.x) return bb;
    return (node){bb.x,aa.n+bb.n};
}
void ad(int o,int x){xzz[o].x+=x,tg[o]+=x;}
void psdn(int o){if(tg[o]) ad(o<<1,tg[o]),ad(o<<1|1,tg[o]),tg[o]=0;}
void modif(int o,int l,int r,int ll,int rr,int x)
{
    if(ll<=l&&r<=rr){ad(o,x);return;}
    psdn(o);
    int mid=(l+r)>>1;
    if(ll<=mid) modif(o<<1,l,mid,ll,rr,x);
    if(rr>mid) modif(o<<1|1,mid+1,r,ll,rr,x);
    xzz[o]=mergg(xzz[o<<1],xzz[o<<1|1]);
}
node quer(int o,int l,int r,int ll,int rr)
{
    if(ll<=l&&r<=rr) return xzz[o];
    psdn(o);
    int mid=(l+r)>>1;
    node aa=xzz[0],bb=xzz[0];
    if(ll<=mid) aa=quer(o<<1,l,mid,ll,rr);
    if(rr>mid) bb=quer(o<<1|1,mid+1,r,ll,rr);
    xzz[o]=mergg(xzz[o<<1],xzz[o<<1|1]);
    return mergg(aa,bb);
}
int qnmd(int o,int l,int r)
{
    if(l==r) return l;
    psdn(o);
    int mid=(l+r)>>1,an=0;
    if(xzz[o<<1|1].x<0) an=qnmd(o<<1|1,mid+1,r);
    else an=qnmd(o<<1,l,mid);
    xzz[o]=mergg(xzz[o<<1],xzz[o<<1|1]);
    return an;
}
void bui(int o,int l,int r)
{
    if(l==r){xzz[o].n=1;return;}
    int mid=(l+r)>>1;
    bui(o<<1,l,mid),bui(o<<1|1,mid+1,r);
    xzz[o]=mergg(xzz[o<<1],xzz[o<<1|1]);
}
void dfs(int x,int de)
{
    f[x]=f[fa[x]];
    modif(1,1,n,1,de,cc[x]==')'?1:-1);
    int ql=xzz[1].x<0?qnmd(1,1,n)+1:1;
    if(ql<=de)
    {
        fkrr=quer(1,1,n,ql,de);
        if(!fkrr.x) f[x]+=fkrr.n;
    }
    ans^=f[x]*x;
    for(int i=hd[x];i;i=nt[i])
    {
        int y=to[i];
        dfs(y,de+1);
    }
    modif(1,1,n,1,de,cc[x]==')'?-1:1);
}

int main()
{
    n=rd();
    scanf("%s",cc+1);
    for(int i=2;i<=n;++i)
    {
        fa[i]=rd();
        add(fa[i],i);
    }
    xzz[0].x=1919810;
    bui(1,1,n);
    dfs(1,1);
    printf("%lld\n",ans);
    return 0;
}

M_sea:你個[],這不是\(O(n)\)傻[]題嗎

其實線段樹是多餘的,考慮對種和開一個桶記錄這種權值的數出現次數,然後每次加入一個點就看這個點導致的整個權值變化,再用當前權值意義下爲0的桶更新答案,不過要注意在之前當前權值意義下爲-1的最後一個數不能計入答案,所以在更新桶的時候注意一下

code ```cpp #include #define LL long long using namespace std; const int N=5e5+10; int rd() { int x=0,w=1;char ch=0; while(ch'9'){if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();} return x*w; } int to[N],nt[N],hd[N],tot=1; void add(int x,int y){++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;} char cc[N]; int n,fa[N],va[N<<1]; LL an[N],ans; void dfs(int x,int o) { int s=o+(cc[x]==')'?-1:1),las=va[o+1]; ++va[o],va[o+1]=0; if(cc[x]==')') an[x]+=va[s]; for(int i=hd[x];i;i=nt[i]) { int y=to[i]; an[y]=an[x],dfs(y,s); } --va[o],va[o+1]=las; } int main() { n=rd(); scanf("%s",cc+1); for(int i=2;i<=n;++i) add(fa[i]=rd(),i); dfs(1,n); for(int i=1;i<=n;++i) ans^=1ll*i*an[i]; printf("%lld\n",ans); return 0; } ```

樹上的數

wtcl,又被這種題送退役了

做法顯然是從小到大枚舉每個數,然後枚舉這個數最終走到的點,如果合法就讓它走過去,現在問題是怎麼判斷合法

考慮一個數從點\(x\)走到\(y\),依次經過的邊爲\(e_1,e_2...e_m\),首先\(e_1\)必須比其他和\(x\)相連的邊先選(如果\(e_1\)已經必須在某些邊後面了,就只管除此以外的其他邊,下面類似),否則這個數會走到別的地方去,並且走不回來,然後中間的\(e_i(1<i\le m)\),一定是比\(e_{i-1}\)後選,並且對於和\(e_{i-1}\)\(e_i\)公共點相連的其他邊,都不能在\(e_{i-1}\)\(e_i\)之間選.最後是\(e_m\),必須在其他和\(y\)相連的邊選完後再選,不然這個數會跑到別的地方去

這裏面比較麻煩的是中間那個其他邊不能在兩條邊之間選,但如果我們只考慮一個點以及它連出去的邊(菊花圖),這個時候我們發現其他邊是不會影響到這個點上的數的,也就是考慮這些邊的相對順序.對於一個菊花,如果要使得其他邊不能在兩條邊之間選,那麼這兩條邊必須選完前面一條後馬上選另一條.那麼上述限制可以抽象成:一條邊必須先選,一條邊必須最後選,兩條邊必須選完一條後馬上選另一條.大概每個點開一個鏈表,維護這個點連出去的邊的先後順序,檢查合法行就看新增的限制是否會和前面限制矛盾

代碼咕了,先胡着再說...

Emiya 家今天的飯

這裏的方案計算只有某一列被選次數不超過\(\lfloor\frac{k}{2}\rfloor\)這個限制不太好直接做,所以考慮容斥,即總方案-不合法方案.總方案爲\(\prod_{i=1}^{n}(1+\sum_{j=1}^{m}a_{i,j})\)

如果有一列被選次數\(>\lfloor\frac{k}{2}\rfloor\),那麼有且僅有這一列會超出限制,所以不合法方案只有一列不滿足限制,那就枚舉超出限制的爲哪一列,然後設\(f_{i,j,k}\)表示考慮前\(i\)行,選了\(j\)次,指定的不合法列選\(k\)次的方案,轉移揹包轉移即可,那麼這一列的貢獻爲\(\sum_{j=1}^{n}\sum_{k=\lfloor\frac{j}{2}\rfloor+1}^{j} f_{n,j,k}\),複雜度\(O(n^3m)\)

考慮優化,如果我們把上述狀態的\(j-k\)\(k\)做差,那麼一個不合法方案,它的這個差一定\(<0\),所以上述狀態改爲\(f_{i,j}\)表示前\(i\)行,其他列出現次數-指定列出現次數爲\(j\)的方案,然後轉移完後用\(j<0\)的統計,即可做到\(O(n^2m)\).實現時注意負下標的處理

code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=100+10,M=2000+10,mod=998244353;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
void ad(int &x,int y){x+=y,x-=x>=mod?mod:0;}
int n,m,a[N][M],s[N],g[2][N],f[2][N<<1],ans;

int main()
{
    n=rd(),m=rd();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            a[i][j]=rd();
            ad(s[i],a[i][j]);
        }
    int nw=1,la=0;
    g[la][0]=1;
    for(int i=1;i<=n;++i)
    {
        for(int j=0;j<i;++j)
        {
            if(!g[la][j]) continue;
            ad(g[nw][j],g[la][j]);
            ad(g[nw][j+1],1ll*g[la][j]*s[i]%mod);
            g[la][j]=0;
        }
        nw^=1,la^=1;
    }
    for(int i=1;i<=n;++i) ad(ans,g[la][i]);
    for(int h=1;h<=m;++h)
    {
        memset(f,0,sizeof(f));
        nw=1,la=0;
        f[la][n]=1;
        for(int i=1;i<=n;++i) s[i]=(s[i]-a[i][h]+mod)%mod;
        for(int i=1;i<=n;++i)
        {
            for(int j=n-i+1;j<=n+i-1;++j)
            {
                if(!f[la][j]) continue;
                ad(f[nw][j],f[la][j]);
                ad(f[nw][j+1],1ll*f[la][j]*s[i]%mod);
                ad(f[nw][j-1],1ll*f[la][j]*a[i][h]%mod);
                f[la][j]=0;
            }
            nw^=1,la^=1;
        }
        for(int i=1;i<=n;++i) ad(s[i],a[i][h]);
        for(int j=n-1;~j;--j) ans=(ans-f[la][j]+mod)%mod;
    }
    printf("%d\n",ans);
    return 0;
}

劃分

先考慮樸素dp,設\(f_{i,j}\)表示上一次選擇的段爲\([j,i]\)的最小值,複雜度\(O(n^3)\),然後注意到一個\(f_{i,j}\),從前面一個位置\(k\)轉移過來\((k=j-1)\),那麼\(f_k\)的合法第二維一定是在\([x,k]\)之間,其中\(x\)爲最大的能轉移到\(f_{i,j}\)的位置,那麼記一下\(f_{i,j}\)關於\(j\)的後綴最小值,即可做到\(O(n^2)\)

然後先丟一個證明鏈接,再不加證明的給出兩個引理

  • 一個\(f_{i,j}\)往後轉移時,一定是用合法的\(j\)最大的\(f_{i,j}\)的轉移到後面,後面記這個最大的\(j\)\(p_i\)
  • 對於一個\(i\),記能從前面轉移過來的位置集合爲\({x}\),那麼最優的轉移位置一定是集合最大值\(k\),即用\(f_{k,p_k}\)轉移到\(f_{i,k+1}\)

你問我爲什麼不給證明,因爲這是打表得到的

這樣對於每個\(i\),二分出它最先可以貢獻的後面的位置(即最小的\(a\)滿足\(sum_a-sum_i\ge sum_i-sum_{p_i-1}\)),把\(i\)丟進對應的決策集合,然後在做到某個位置時用這個位置的決策更新最優決策,可以做到\(O(nlogn)\)

但這個二分是可以去掉的,我們維護一個單調隊列,維護還沒加入的決策\(i\),這些\(i\)以對應的\(sum_i-sum_{p_i-1}\)爲關鍵字,每次加入一個決策進隊列就把隊尾的一定比這個決策差的決策彈掉(設隊尾對應元素爲\(t\)\(sum_i-sum_{p_i-1}<=sum_t-sum_{p_t-1}-(sum_i-sum_t)\)時彈隊尾),然後壓進隊尾,每次用隊首能加入的決策更新當前決策

同時你還需要實現一個高精,所以請注意常數問題.我這裏用的是4個\(\text{int}\)表示\(32\)位整數

code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=4e7+10,mod=1e9;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
int n;
LL bk[4],s[N],va[N];
struct NUM
{
    int a0,a1,a2,a3;
    void clr(){a0=a1=a2=a3=0;}
    NUM operator + (const LL &bb) const
    {
        bk[0]=a0+bb,bk[1]=a1,bk[2]=a2,bk[3]=a3;
        bk[1]+=bk[0]/mod,bk[0]%=mod;
        bk[2]+=bk[1]/mod,bk[1]%=mod;
        bk[3]+=bk[2]/mod,bk[2]%=mod;
        return (NUM){bk[0],bk[1],bk[2],bk[3]};
    }
    NUM operator + (const NUM &bb) const
    {
        NUM aa=(NUM){a0,a1,a2,a3};
        aa.a0+=bb.a0,aa.a1+=aa.a0/mod,aa.a0%=mod;
        aa.a1+=bb.a1,aa.a2+=aa.a1/mod,aa.a1%=mod;
        aa.a2+=bb.a2,aa.a3+=aa.a2/mod,aa.a2%=mod;
        aa.a3+=bb.a3;
        return aa;
    }
    NUM operator - (const NUM &bb) const
    {
        NUM aa=(NUM){a0,a1,a2,a3};
        while(aa.a0<bb.a0) --aa.a1,aa.a0+=mod;
        aa.a0-=bb.a0;
        while(aa.a1<bb.a1) --aa.a2,aa.a1+=mod;
        aa.a1-=bb.a1;
        while(aa.a2<bb.a2) --aa.a3,aa.a2+=mod;
        aa.a2-=bb.a2;
        aa.a3-=bb.a3;
        return aa;
    }
    NUM operator * (const NUM &bb) const
    {
        bk[0]=1ll*a0*bb.a0;
        bk[1]=1ll*a0*bb.a1+1ll*a1*bb.a0;
        bk[2]=1ll*a1*bb.a1;
        bk[3]=0;
        bk[1]+=bk[0]/mod,bk[0]%=mod;
        bk[2]+=bk[1]/mod,bk[1]%=mod;
        bk[3]+=bk[2]/mod,bk[2]%=mod;
        return (NUM){bk[0],bk[1],bk[2],bk[3]};
    }
    void print()
    {
        int an[40],ta=0;
        NUM aa=*this;
        for(int i=1;i<=9;++i) an[++ta]=aa.a0%10,aa.a0/=10;
        for(int i=1;i<=9;++i) an[++ta]=aa.a1%10,aa.a1/=10;
        for(int i=1;i<=9;++i) an[++ta]=aa.a2%10,aa.a2/=10;
        for(int i=1;i<=9;++i) an[++ta]=aa.a3%10,aa.a3/=10;
        while(ta>1&&!an[ta]) --ta;
        while(ta) printf("%d",an[ta--]);
    }
}sb,ans;
int p[N],q[N],hd=1,tl;
void wk()
{
    p[1]=1;
    va[1]=s[1],q[++tl]=1;
    for(int i=2;i<=n;++i)
    {
        p[i]=p[i-1];
        while(hd<=tl&&va[q[hd]]<=s[i]-s[q[hd]]) p[i]=max(p[i],q[hd]+1),++hd;
        va[i]=s[i]-s[p[i]-1];
        while(hd<=tl&&va[i]<=va[q[tl]]-(s[i]-s[q[tl]])) --tl;
        q[++tl]=i;
    }
    for(int x=n;x;x=p[x]-1)
    {
        sb.clr();
        sb=sb+(s[x]-s[p[x]-1]);
        ans=ans+sb*sb;
    }
    ans.print();
}
int sx,sy,sz,yyb[2],m,xz[100010][3],md=1<<30;

int main()
{
    n=rd();
    int jntm=rd();
    int jj=1;
    if(!jntm)
    {
        for(int i=1;i<=n;++i)
        {
            int xx=rd();
            s[i]=s[i-1]+xx;
        }
    }
    else
    {
        sx=rd(),sy=rd(),sz=rd(),yyb[0]=rd(),yyb[1]=rd(),m=rd();
        int nw=0,la=1;
        for(int i=1;i<=m;++i)
            for(int j=0;j<=2;++j)
                xz[i][j]=rd();
        while(xz[jj][0]<1) ++jj;
        s[1]=s[0]+(yyb[0]%(xz[jj][2]-xz[jj][1]+1)+xz[jj][1]);
        while(xz[jj][0]<2) ++jj;
        s[2]=s[1]+(yyb[1]%(xz[jj][2]-xz[jj][1]+1)+xz[jj][1]);
        for(int i=3;i<=n;++i)
        {
            yyb[nw]=(1ll*sx*yyb[la]+1ll*sy*yyb[nw]+sz)%md;
            while(xz[jj][0]<i) ++jj;
            s[i]=s[i-1]+(yyb[nw]%(xz[jj][2]-xz[jj][1]+1)+xz[jj][1]);
            nw^=1,la^=1;
        }
    }
    wk();
    return 0;
}

樹的重心

初賽時認爲完全二叉樹就是滿二叉樹,然後這道題以爲完美二叉樹不是滿二叉樹,然後GG QAQ

考慮樸素做法,枚舉鴿的是哪條邊,然後對於剩下兩個子樹分別求重心,具體操作是分別以兩個點爲根,然後從根出發,走到第一個點滿足最大的兒子子樹大小\(\le \lfloor\frac{size}{2}\rfloor\).如果有兩個重心,則說明當前走到的點最大的兒子子樹大小\(=\lfloor\frac{size}{2}\rfloor\),那麼另一個重心爲對應子樹大小最大的兒子

如果套用以上做法,然後隨便設一個點爲根,那麼可以統計出鴿掉每條邊後,靠下面的點(記爲\(y\))的子樹的重心貢獻,在往兒子走的時候加一個倍增優化即可.然後還有被鴿邊上面那個點(記爲\(x\))的貢獻,那麼可以看做是把\(x\)作爲根,然後不考慮\(y\)的子樹,然後往兒子走的過程,所以可以考慮換根dfs,因爲在dfs到某個點的時候,只有這個點到根路徑上的點的父子關係變化了,所以每次枚舉這個點的兒子\(y\)時,\(x\)爲根時的兒子實際上是\(x\)在原樹中的其他兒子和\(x\)的父親,那麼倍增數組只要用這些\(x\)爲根時的兒子預處理就好了.具體實現的時候,如果\(y\)爲子樹大小最大的兒子,那麼\(x\)下一步走的是父親或者子樹大小次大兒子,否則是父親或者子樹大小最大兒子

code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=3e5+10;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
int to[N<<1],nt[N<<1],hd[N],dg[N],tot=1;
void add(int x,int y)
{
    ++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
    ++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
}
int n,lz,fa[N],sz[N],hs[N],va[N],f[N][19],g[N][19];
LL ans;
void dfs(int x)
{
    sz[x]=1,va[x]=0;
    for(int i=hd[x];i;i=nt[i])
    {
        int y=to[i];
        if(y==fa[x]) continue;
        fa[y]=x,dfs(y),sz[x]+=sz[y];
    }
    hs[x]=0;
    for(int i=hd[x];i;i=nt[i])
    {
        int y=to[i];
        if(y==fa[x]) continue;
        if(sz[hs[x]]<sz[y]) hs[x]=y;
    }
    va[x]=sz[hs[x]],g[x][0]=hs[x];
    for(int j=1;j<=lz;++j) g[x][j]=g[g[x][j-1]][j-1];
    if(!fa[x]) return;
    int xx=x,lm=sz[x]/2;
    for(int j=lz;~j;--j)
        if(va[g[xx][j]]>lm) xx=g[xx][j];
    if(va[xx]>lm) xx=g[xx][0];
    if(sz[x]%2==0&&va[xx]==lm) xx+=g[xx][0];
    ans+=xx;
}
void dfs2(int x)
{
    int las=va[x];
    if(hs[x])
    {
        if(fa[x]) f[x][0]=fa[x],va[x]=n-sz[x];
        else f[x][0]=va[x]=0;
        for(int i=hd[x];i;i=nt[i])
        {
            int y=to[i];
            if(y!=hs[x]&&y!=fa[x]&&sz[y]>va[x]) f[x][0]=y,va[x]=sz[y];
        }
        for(int j=1;j<=lz;++j) f[x][j]=f[f[x][j-1]][j-1];
        int xx=x,y=hs[x],lm=(n-sz[y])/2;
        for(int j=lz;~j;--j)
            if(va[f[xx][j]]>lm) xx=f[xx][j];
        if(va[xx]>lm) xx=f[xx][0];
        if((n-sz[y])%2==0&&va[xx]==lm) xx+=f[xx][0];
        ans+=xx;
        dfs2(y);
    }
    if(sz[hs[x]]>n-sz[x]) f[x][0]=hs[x],va[x]=sz[hs[x]];
    else f[x][0]=fa[x],va[x]=n-sz[x];
    for(int j=1;j<=lz;++j) f[x][j]=f[f[x][j-1]][j-1];
    for(int i=hd[x];i;i=nt[i])
    {
        int y=to[i];
        if(y==fa[x]||y==hs[x]) continue;
        int xx=x,lm=(n-sz[y])/2;
        for(int j=lz;~j;--j)
            if(va[f[xx][j]]>lm) xx=f[xx][j];
        if(va[xx]>lm) xx=f[xx][0];
        if((n-sz[y])%2==0&&va[xx]==lm) xx+=f[xx][0];
        ans+=xx;
        dfs2(y);
    }
    memcpy(f[x],g[x],sizeof(g[x])),va[x]=las;
}

int main()
{
    int T=rd();
    while(T--)
    {
        n=rd(),lz=log2(n),ans=0;
        memset(hd,0,sizeof(int)*(n+3)),memset(fa,0,sizeof(int)*(n+3)),tot=1;
        for(int i=1;i<n;++i) add(rd(),rd());
        memset(g,0,sizeof(g));
        dfs(1);
        for(int i=1;i<=n;++i) memcpy(f[i],g[i],sizeof(g[i]));
        dfs2(1);
        printf("%lld\n",ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章