2025多校冲刺省选模拟赛15 && 2025省选模拟12

2025多校冲刺省选模拟赛15

\(T1\) A. 小 F 的疑惑

  • 原题: TopCoder 12584 SemiPerfectPower

  • 每个半幂数都可以表示成 \(c=2/3\) 的情况,不妨分开考虑。

  • \(f(i)\) 表示 \(i\) 最大的平方因子, \(g(i)\) 表示 \(i\) 是否存在非 \(1\) 的立方因子。

  • \(c=2\) :设 \(n=ab^{2}(f(a)=1,a<b)\) ,移项得到 \(a<\sqrt[3]{n}\) ,直接枚举 \(a\) 即可。

  • \(c=3\) :设 \(n=ab^{3}(g(a)=0,a<b)\) ,移项得到 \(a<\sqrt[4]{n}\) ,直接枚举 \(a\) 即可。

  • 此时两部分还会有重复的部分,以 \(c=3\) 为例, \(n=ab^{3}\) 不能表示成 \(n=a'b'^{2}\) 的充要条件为 \(f(n) \le \sqrt[3]{n}\) 。又因为 \(f(n)=f(ab)b\) 得到 \(f(ab) \le \sqrt[3]{a}<\sqrt[12]{n}\)

  • 类似地,有 \(f(ab)=f(a)f(\frac{b}{\gcd(\frac{a}{f^{2}(a)},b)})\gcd(\frac{a}{f^{2}(a)},b)<\sqrt[12]{n}\) 。令 \(d=\gcd(\frac{a}{f^{2}(a)},b),t=f(\frac{b}{d})\) ,考虑枚举 \(b \in [a+1,\sqrt[3]{\frac{n}{a}}]\)\(\gcd(\frac{b}{d},\frac{a}{f^{2}(a)d})=1 \land f(a)dt \le \sqrt[3]{a}\)

  • 枚举 \(a,d,t(\gcd(\frac{a}{f^{2}(a)d},t)=1)\) 后将式子再做变形得到 \(b=kdt^{2},k \in [\dfrac{a+1}{dt^{2}},\dfrac{\sqrt[3]{\frac{n}{a}}}{dt^{2}}] \land f(k)=1 \land \gcd(k,\frac{a}{f^{2}(a)d})=1\) 。莫反后有 \(\sum\limits_{i|\frac{a}{f^{2}(a)d}} \mu(i)\sum\limits_{k=\frac{a+1}{dt^{2}}}^{\frac{\sqrt[3]{\frac{n}{a}}}{dt^{2}}}[i|k \land f(k)=1]\) 。其中后半部分可以转化成 \(\sum\limits_{k=1}^{\frac{n}{i}}[f(ik)=1]\) 的形式。

  • 略卡精度。

    点击查看代码
    ll prime[450010],vis[450010],miu[450010],f[450010],g[450010],len=0;
    vector<ll>di[450010],s[450010];
    void isprime(ll n)
    {
        for(ll i=1;i*i<=n;i++)
        {
            for(ll j=i*i;j<=n;j+=i*i)  f[j]=i;
        }
        for(ll i=2;i*i*i<=n;i++)
        {
            for(ll j=i*i*i;j<=n;j+=i*i*i)  g[j]=1;
        }
        for(ll i=1;i<=n;i++)
        {
            for(ll j=i;j<=n;j+=i)  di[j].push_back(i);
        }
        memset(vis,0,sizeof(vis));
        miu[1]=1;
        for(ll i=2;i<=n;i++)
        {
            if(vis[i]==0)
            {
                len++;  prime[len]=i;
                miu[i]=-1;
            }
            for(ll j=1;j<=len&&i*prime[j]<=n;j++)
            {
                vis[i*prime[j]]=1;
                if(i%prime[j]==0)
                {
                    miu[i*prime[j]]=0;
                    break;
                }
                else  miu[i*prime[j]]=-miu[i];
            }
        }
        for(ll i=1;i<=n;i++)
        {
            if(miu[i]!=0)
            {
                s[i].push_back(0);
                for(ll j=1;i*j<=n;j++)  s[i].push_back(s[i].back()+(f[i*j]==1));
            }
        }
    }
    ll solve(ll n)
    {
        ll ans=0,tmp,x,y,d,o,l,r;
        for(ll a=1;a*a*a<n;a++)
        {
            if(f[a]==1)  ans+=max(0ll,(ll)(sqrt(n/a))-a);
        } 
        for(ll a=1;a*a*a*a<n;a++)
        {
            if(g[a]==0)
            {
                tmp=a/f[a]/f[a];
                for(x=pow(a,1.0/3);x*x*x<=a;x++);
                for(;x*x*x>a;x--); 
                for(y=pow(n/a,1.0/3);a*y*y*y<=n;y++);
                for(;a*y*y*y>n;y--);
                for(ll j=0;j<di[tmp].size();j++)
                {
                    d=di[tmp][j];
                    for(ll k=0;k<di[d].size();k++)
                    {
                        o=di[d][k];
                        if(o*f[a]>x)  break;
                        for(ll t=1;t<=x/o/f[a];t++)
                        {
                            if(__gcd(t,tmp/o)==1)
                            {
                                l=a/d/t/t;  r=y/d/t/t;
                                ans+=miu[d/o]*(s[d/o][r]-s[d/o][l]);
                            }
                        }
                    }
                }
            }
        }
        return ans;
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("power.in","r",stdin);
        freopen("power.out","w",stdout);
    #endif
        ll t,l,r,i;
        cin>>t;  isprime(450000);
        for(i=1;i<=t;i++)
        {
            cin>>l>>r;
            cout<<solve(r)-solve(l-1)<<endl;
        }
        return 0;
    }
    

\(T2_{1}\) B. 城市规划

  • 原题: TopCoder 13518 CityRebuild

  • 详见 2025省选模拟8 T1 HZTG5836. 小幸运

  • 数据中提到了可能会有重复的点,但一些 Corner Case 还是没卡。

  • 需要借助 inline#pragma GCC optimize(3) 的力量。

    点击查看代码
    #pragma GCC optimize(3)
    const ll dx[4][3]={{1,0,0},{1,0,0},{-1,0,0},{-1,0,0}},dy[4][3]={{0,-1,0},{0,1,0},{0,-1,0},{0,1,0}};
    ll dfn[1610],low[1610],ins[1610],col[1610],x[2][3],y[2][3],tot,scc_cnt,n,w,h;
    pair<ll,ll>a[1610],z[2][3];
    stack<ll>s;
    vector<ll>e[1610];
    inline void add(ll u,ll v)
    {
        e[u].push_back(v);
    }
    inline void tarjan(ll x)
    {
        tot++;  dfn[x]=low[x]=tot;
        ins[x]=1;  s.push(x);
        for(ll i=0;i<e[x].size();i++)
        {
            if(dfn[e[x][i]]==0)
            {
                tarjan(e[x][i]);
                low[x]=min(low[x],low[e[x][i]]);
            }
            else
            {
                if(ins[e[x][i]]==1)
                {
                    low[x]=min(low[x],dfn[e[x][i]]);
                }
            }
        }
        if(dfn[x]==low[x])
        {
            scc_cnt++;
            ll tmp=0;
            while(x!=tmp)
            {
                tmp=s.top();
                ins[tmp]=0;
                col[tmp]=scc_cnt;
                s.pop();
            }
        }
    }
    inline bool out_of_bounds(ll x,ll y,ll op,ll mid)
    {
        for(ll i=0;i<=1;i++)
        {
            if(x+dx[op][i]*mid<0||x+dx[op][i]*mid>w||y+dy[op][i]*mid<0||y+dy[op][i]*mid>h)  return true;
        }
        return false;
    }
    inline bool line_cross(ll x1,ll y1,ll x2,ll y2,ll _x1,ll _y1,ll _x2,ll _y2)
    {
        if(x1==x2&&_x1==_x2)  
        {
            return ((x1==_x1)&&((min(y1,y2)<_y1&&_y1<max(y1,y2))||(min(y1,y2)<_y2&&_y2<max(y1,y2))));
        }	
        if(_x1==_x2)
        {
            swap(x1,_x1);  swap(y1,_y1);
            swap(x2,_x2);  swap(y2,_y2);
        }
        if(x1==x2)
        {
            double _k=1.0*(_y2-_y1)/(_x2-_x1),_b=_y1-_x1*_k,y=_k*x1+_b;
            return (_x1<x1&&x1<_x2&&min(y1,y2)<y&&y<max(y1,y2));
        }
        double k=1.0*(y2-y1)/(x2-x1),b=y1-x1*k,_k=1.0*(_y2-_y1)/(_x2-_x1),_b=_y1-_x1*_k;
        if(k==_k)  return false;
        double x=(_b-b)/(k-_k);
        return (min(x1,x2)<x&&x<max(x1,x2)&&min(_x1,_x2)<x&&x<max(_x1,_x2));
    }
    inline bool triangle_cross(ll x1,ll y1,ll op1,ll x2,ll y2,ll op2,ll mid)
    {
        for(ll i=0;i<=2;i++)  
        {
            x[0][i]=x1+dx[op1][i]*mid;  y[0][i]=y1+dy[op1][i]*mid;
            x[1][i]=x2+dx[op2][i]*mid;  y[1][i]=y2+dy[op2][i]*mid;
        }
        for(ll i=0;i<=2;i++)
        {
            for(ll j=0;j<=2;j++)
            {
                if(line_cross(x[0][i],y[0][i],x[0][(i+1)%3],y[0][(i+1)%3],
                            x[1][j],y[1][j],x[1][(j+1)%3],y[1][(j+1)%3])==true)
                {
                    return true;
                }
            }
        }
        return false;
    }
    inline bool check(ll mid)
    {
        for(ll i=1;i<=8*n;i++)  e[i].clear();
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(ins,0,sizeof(ins));
        memset(col,0,sizeof(col));
        tot=scc_cnt=0;
        while(s.empty()==0)  s.pop();
        for(ll i=1;i<=n;i++)
        {
            for(ll j=0;j<=3;j++)
            {
                add(i+j*n,i+(3-j)*n+4*n);  add(i+j*n+4*n,i+(3-j)*n);
                if(out_of_bounds(a[i].first,a[i].second,j,mid)==true)  add(i+j*n,i+j*n+4*n);
            }
        }
        for(ll i=1;i<=n;i++)
        {
            for(ll j=i+1;j<=n;j++)
            {
                for(ll u=0;u<=3;u++)
                {
                    for(ll v=0;v<=3;v++)
                    {
                        if((a[i]==a[j]&&u==v)||triangle_cross(a[i].first,a[i].second,u,
                                        a[j].first,a[j].second,v,mid)==true)
                        {
                            add(i+u*n,j+v*n+4*n);  add(j+v*n,i+u*n+4*n);
                        }
                    }
                }
            }
        }
        for(ll i=1;i<=8*n;i++)  if(dfn[i]==0)  tarjan(i);
        for(ll i=1;i<=4*n;i++)  if(col[i]==col[i+4*n])  return false;
        return true;
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("city.in","r",stdin);
        freopen("city.out","w",stdout);
    #endif
        ll l=0,r,ans=0,mid,i;
        cin>>w>>h>>n;  r=min(w,h);
        w*=2;  h*=2;
        for(i=1;i<=n;i++)  
        {
            cin>>a[i].first>>a[i].second;
            a[i].first*=2;  a[i].second*=2;
        }
        while(l<=r)
        {
            mid=(l+r)/2;
            if(check(mid)==true)
            {
                ans=mid;
                l=mid+1;
            }
            else
            {
                r=mid-1;
            }
        }
        cout<<ans<<".00"<<endl;
        return 0;
    }
    

\(T2_{2}\) HZTG5883. 机关

\(T2_{3}\) HZTG3024. 发烧(fever)

\(T3\) C. 小 F 的序列

  • 原题: luogu P4224 [清华集训 2017] 简单数据结构

  • 观察到 \(m \le 10^{6}\)\(c=10\) ,提示我们可行的修改点不会很多,考虑从值域入手。

  • 最长上升倍数子序列长度规模为 \(O(\log n)\) ,可以直接枚举。

  • \(f_{x}\) 表示以 \(x\) 开头的最长上升倍数子序列长度, \(cnt_{x,len}\) 表示以 \(x\) 开头的极长上升倍数子序列长度为 \(len\) 的方案数, \(g_{len}\) 表示上升倍数子序列长度为 \(len\) 的方案数。

    • \(cnt_{x,len}\) 的更新建议参考代码理解。
  • 从左端插入/删除直接枚举倍数即可;从右段进行操作时观察到每个点的答案至多变化 \(1\) ,从高到低枚举约数执行形如链式的更新即可。

  • 可以只记录合法的转移点来减小常数。

    点击查看代码
    int a[400010],op[100010],x[100010],vis[1000010],pos[1000010],f[400010],g[25],cnt[400010][25];
    vector<int>d[1000010];
    void print()
    {
        int ans=1;
        for(int i=1;i<=22;i++)  if(g[i]!=0)  ans=i;
        printf("%d %d\n",ans,g[ans]);
    }
    void push_front(int x,int y,int m)
    {
        a[x]=y;  pos[a[x]]=x;
        memset(cnt[x],0,sizeof(cnt[x]));
        cnt[x][1]=f[x]=1;
        for(int i=a[x]*2;i<=m;i+=a[x])  
        {
            if(pos[i]!=0)  
            {
                cnt[x][f[pos[i]]+1]++;
                f[x]=max(f[x],f[pos[i]]+1);
            }
        }
        g[f[x]]++;
    }
    void push_back(int x,int y)
    {
        a[x]=y;  pos[a[x]]=x;
        cnt[x][1]=f[x]=1;  g[f[x]]++;
        for(int i=0;i<d[a[x]].size();i++)
        {
            int y=pos[d[a[x]][i]];
            if(y!=0)
            {
                cnt[y][2]++;
                if(cnt[y][f[y]+1]!=0)
                {
                    g[f[y]]--;
                    f[y]++;  g[f[y]]++;
                    for(int j=0;j<d[a[y]].size();j++)
                    {
                        int z=pos[d[a[y]][j]];
                        if(z!=0&&z<y)
                        {
                            cnt[z][f[y]]--;  cnt[z][f[y]+1]++;
                        }
                    }
                }
            }
        }
    }
    void pop_front(int x)
    {
        pos[a[x]]=0;  g[f[x]]--;
    }
    void pop_back(int x)
    {
        pos[a[x]]=0;  g[f[x]]--;
        for(int i=0;i<d[a[x]].size();i++)
        {
            int y=pos[d[a[x]][i]];
            if(y!=0)
            {
                cnt[y][2]--;
                if(cnt[y][f[y]]==0)
                {
                    g[f[y]]--;
                    f[y]--;  g[f[y]]++;
                    for(int j=0;j<d[a[y]].size();j++)
                    {
                        int z=pos[d[a[y]][j]];
                        if(z!=0&&z<y)
                        {
                            cnt[z][f[y]+2]--;  cnt[z][f[y]+1]++;
                        }
                    }
                }
            }
        }
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("seq.in","r",stdin);
        freopen("seq.out","w",stdout);
    #endif
        int n,m,q,l,r,i,j;
        scanf("%d%d%d",&n,&m,&q);  l=q+1;  r=q+n;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[q+i]);  vis[a[q+i]]=1;
        }
        for(i=1;i<=q;i++)
        {
            scanf("%d",&op[i]);
            if(op[i]<=1)
            {
                scanf("%d",&x[i]);  vis[x[i]]=1;
            }
        }
        for(i=m;i>=1;i--)
        {
            if(vis[i]==1)
            {
                for(j=2*i;j<=m;j+=i)  if(vis[j]==1)  d[j].push_back(i);
            }
        }
        for(i=l;i<=r;i++)  push_back(i,a[i]);
        print();
        for(i=1;i<=q;i++)
        {
            if(op[i]==0)  
            {
                l--;  push_front(l,x[i],m);
            }
            if(op[i]==1)  
            {
                r++;  push_back(r,x[i]);
            }
            if(op[i]==2)
            {
                pop_front(l);  l++;
            }
            if(op[i]==3)
            {
                pop_back(r);  r--;
            }
            print();
        }
        return 0;
    }
    

2025省选模拟12

\(T1\) P1019. 国际象棋 \(0pts\)

  • 观察到每条对角线上有且仅有一个 \(0\) ,且合法局面下的 \(0\) 一定构成了一段从 \((n,1)\)\((1,m)\) 的路径,途中不经过 \(1\)

  • 从下往上考虑每条对角线的贡献,如果有 \(0\) ,那么其他位置上一定是 \(1\) ,分段统计不经过 \(1\) 的方案数即可。

    点击查看代码
    const int p=1000000007;
    int f[5010][5010],sx[10010],sy[10010],cnt[10010];	
    char s[5010][5010];
    int solve(int x1,int y1,int x2,int y2)
    {
        f[x1][y1]=1;
        for(int i=x1;i<=x2;i++)
        {
            for(int j=y1;j<=y2;j++)  
            {
                if(i+1<=x2&&s[i+1][j]!='1')  f[i+1][j]=(f[i+1][j]+f[i][j])%p;
                if(j+1<=y2&&s[i][j+1]!='1')  f[i][j+1]=(f[i][j+1]+f[i][j])%p;
            }
        }
        return (x1<=x2&&y1<=y2)*f[x2][y2];
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("chess.in","r",stdin);
        freopen("chess.out","w",stdout);
    #endif
        int n,m,ans=1,x=1,y=1,i,j;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)  cin>>s[n-i+1][j];
        }
        if(s[1][1]=='1'||s[n][m]=='1')  cout<<0<<endl;
        else
        {
            s[1][1]=s[n][m]='0';
            for(i=1;i<=n;i++)
            {
                for(j=1;j<=m;j++)  
                {
                    if(s[i][j]=='0')  
                    {
                        cnt[i+j]++;
                        sx[i+j]=i;  sy[i+j]=j;
                    }
                }
            }
            for(i=3;i<=n+m&&ans!=0;i++)
            {
                if(cnt[i]>=2)  ans=0;
                if(cnt[i]==1)
                {
                    ans=1ll*ans*solve(x,y,sx[i],sy[i])%p;
                    x=sx[i];  y=sy[i];
                }
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    

\(T2_{1}\) P1028. 好段子

  • 因为没有 \(std\) 和数据,所以只好口胡。

    • 顺延 CF997E Good Subsegments 中扫描线后线段树维护历史版本和的做法,将计算被加了多少次的懒惰标记(时间懒惰标记)从原来的 \(+1\) 改成 \(+r\) 即可。
    • 极限数据下跑了 \(0.6s\) ,如果需要进一步卡常的话就把部分 long long 改成 int 。答案值域达到了 \(4.17 \times 10^{16}\) ,可能需要 unsigned long long
    点击查看代码
    ll a[500010],ans[500010];
    vector<pair<ll,ll> >q[500010];
    stack<ll>s1,s2;
    struct SMT
    {
        struct SegmentTree
        {
            ll minn,num,hsum,tlazy,lazy;
        }tree[2000010];
        #define lson(rt) (rt<<1)
        #define rson(rt) (rt<<1|1)
        void pushup(ll rt)
        {
            tree[rt].minn=min(tree[lson(rt)].minn,tree[rson(rt)].minn);
            tree[rt].num=(tree[lson(rt)].minn==tree[rt].minn)*tree[lson(rt)].num+(tree[rson(rt)].minn==tree[rt].minn)*tree[rson(rt)].num;
            tree[rt].hsum=tree[lson(rt)].hsum+tree[rson(rt)].hsum;
        }
        void build(ll rt,ll l,ll r)
        {
            if(l==r)
            {
                tree[rt].minn=0;  tree[rt].num=1;
                return;
            }
            ll mid=(l+r)/2;
            build(lson(rt),l,mid);  build(rson(rt),mid+1,r);
            pushup(rt);
        }
        void pushlazy(ll rt,ll lazy,ll tlazy,ll minn)
        {
            tree[rt].minn+=lazy;  tree[rt].lazy+=lazy;
            if(tree[rt].minn==minn)
            {
                tree[rt].hsum+=tlazy*tree[rt].num;
                tree[rt].tlazy+=tlazy;
            }
        }
        void pushdown(ll rt)
        {
            pushlazy(lson(rt),tree[rt].lazy,tree[rt].tlazy,tree[rt].minn);
            pushlazy(rson(rt),tree[rt].lazy,tree[rt].tlazy,tree[rt].minn);
            tree[rt].lazy=tree[rt].tlazy=0;
        }
        void update_val(ll rt,ll l,ll r,ll x,ll y,ll val)
        {
            if(x<=l&&r<=y)
            {
                tree[rt].minn+=val;  tree[rt].lazy+=val;
                return;
            }
            pushdown(rt);
            ll mid=(l+r)/2;  
            if(x<=mid)  update_val(lson(rt),l,mid,x,y,val);
            if(y>mid)  update_val(rson(rt),mid+1,r,x,y,val);
            pushup(rt);
        }
        void update_tim(ll rt,ll l,ll r,ll x,ll y,ll val)
        {
            if(x<=l&&r<=y)
            {
                if(tree[rt].minn==0)
                {
                    tree[rt].hsum+=val*tree[rt].num;
                    tree[rt].tlazy+=val;
                }
                return;
            }
            pushdown(rt);
            ll mid=(l+r)/2;
            if(x<=mid)  update_tim(lson(rt),l,mid,x,y,val);
            if(y>mid)  update_tim(rson(rt),mid+1,r,x,y,val);
            pushup(rt);
        }
        ll query(ll rt,ll l,ll r,ll x,ll y)
        {
            if(x<=l&&r<=y)  return tree[rt].hsum;
            pushdown(rt);
            ll mid=(l+r)/2,ans=0;
            if(x<=mid)  ans+=query(lson(rt),l,mid,x,y);
            if(y>mid)  ans+=query(rson(rt),mid+1,r,x,y);
            return ans;
        }
    }T;
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("seq.in","r",stdin);
        freopen("seq.out","w",stdout);
    #endif
        ll n,m,l,r,tmp,i,j;
        scanf("%lld",&n);
        for(i=1;i<=n;i++)  scanf("%lld",&a[i]);
        scanf("%lld",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%lld%lld",&l,&r);
            q[r].push_back(make_pair(l,i));
        }
        T.build(1,1,n);
        for(i=1;i<=n;i++)
        {
            while(s1.empty()==0&&a[s1.top()]>a[i])
            {
                tmp=s1.top();  s1.pop();
                T.update_val(1,1,n,((s1.empty()==0)?s1.top():0)+1,tmp,a[tmp]-a[i]);
            }
            while(s2.empty()==0&&a[s2.top()]<a[i])
            {
                tmp=s2.top();  s2.pop();
                T.update_val(1,1,n,((s2.empty()==0)?s2.top():0)+1,tmp,a[i]-a[tmp]);
            }
            s1.push(i);  s2.push(i);
            if(i-1>=1)  T.update_val(1,1,n,1,i-1,-1);
            T.update_tim(1,1,n,1,i,i);
            for(j=0;j<q[i].size();j++)  ans[q[i][j].second]=T.query(1,1,n,q[i][j].first,i);
        }
        for(i=1;i<=m;i++)  printf("%lld\n",ans[i]);
        return 0;
    }
    

\(T2_{2}\) P1020. 樱花树 \(20pts\)

  • 原题: luogu P8935 [JRKSJ R7] 茎

  • 先不管某个点在操作序列上是否出现及出现在哪个位置,在加入答案时再选择是否要加入操作序列。

  • \(f_{x,i}\) 表示以 \(x\) 为根的子树内进行 \(i\) 次操作不必全部删完的方案数,可以先不管 \(x\) 的影响树形背包转移,然后再通过 \(f_{x,i} \gets f_{x,i-1}+f_{x,i}\) 算入 \(x\) 的影响。设 \(g_{x,i}\) 表示以 \(x\) 为根的子树内进行 \(i\) 次操作不必全部删完,其中不操作 \(1 \to x\) 这条根链上的点的方案数,转移同理。

  • 对于 \(1 \to x\) 这条根链上的点,如果加入操作序列则往下走的所有点后续不可能再被加入。进行特殊转移,若当前节点不操作则可以直接继承父亲节点的信息,否则一个后缀都可以进行转移,使用后缀和优化优化时间复杂度。接着类似背包将不操作 \(1 \to x\) 这条根链上的点的贡献统计即可。

    点击查看代码
    const int p=1000000007;
    struct node
    {
        int nxt,to;
    }e[10010];
    int head[5010],siz[5010],f[5010][5010],C[5010][5010],w[5010],g[2][5010],vis[5010],cnt=0;
    vector<int>s,d;
    void add(int u,int v)
    {
        cnt++;  e[cnt]=(node){head[u],v};  head[u]=cnt;
    }
    void dfs(int x,int fa,int _x)
    {
        s.push_back(x);
        if(x==_x)  d=s;
        f[x][0]=1;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {	
            if(e[i].to!=fa)
            {
                dfs(e[i].to,x,_x);
                for(int j=siz[x];j>=0;j--)
                {
                    for(int k=siz[e[i].to];k>=1;k--)
                        f[x][j+k]=(f[x][j+k]+1ll*f[x][j]*f[e[i].to][k]%p*C[j+k][k]%p)%p;
                }
                siz[x]+=siz[e[i].to];
            }
        }
        siz[x]++;
        for(int i=siz[x];i>=1;i--)  f[x][i]=(f[x][i-1]+f[x][i])%p;
        s.pop_back();
    }
    int del(int x)
    {
        memset(w,0,sizeof(w));
        w[0]=1;
        int siz_x=0;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {	
            if(vis[e[i].to]==0)
            {
                siz_x+=siz[e[i].to];
                for(int j=siz_x;j>=0;j--)
                {
                    for(int k=siz[e[i].to];k>=1;k--)
                        w[j+k]=(w[j+k]+1ll*w[j]*f[e[i].to][k]%p*C[j+k][k]%p)%p;
                }
            }
        }
        return siz_x;
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("tree.in","r",stdin);
        freopen("tree.out","w",stdout);
    #endif
        int n,m,x,u,v,siz_x,sum,i,j,k;
        cin>>n>>m>>x;
        C[0][0]=C[1][0]=C[1][1]=1;
        for(i=2;i<=n;i++)
        {
            cin>>u>>v;
            add(u,v);  add(v,u);
            C[i][0]=1;
            for(j=1;j<=i;j++)  C[i][j]=(C[i-1][j-1]+C[i-1][j])%p;
        }	
        dfs(1,0,x);
        for(i=0;i<d.size();i++)  vis[d[i]]=1;
        del(1);	
        for(i=0;i<=n-1;i++)  g[0][i]=w[i];
        for(i=1;i<d.size();i++)
        {
            siz_x=del(d[i]);  sum=0;
            for(j=n-1;j>=0;j--)
            {
                sum=(sum+g[(i-1)&1][j])%p;
                if(i==d.size()-1)  g[i&1][j]=sum;
                else  g[i&1][j]=(g[(i-1)&1][j]+sum)%p;
            }
            for(j=n-1;j>=0;j--)
            {
                if(g[(i-1)&1][j]!=0)
                {
                    for(k=siz_x;k>=1;k--)
                        if(j+k<=n-1)  g[i&1][j+k]=(g[i&1][j+k]+1ll*g[i&1][j]*w[k]%p*C[j+k][k]%p)%p;	
                }
            }
        }
        cout<<g[(d.size()-1)&1][m-1]<<endl;
        return 0;
    }
    

\(T3\) P1021. 长颈鹿会面 \(15pts\)

总结

  • 参赛体验极差。
    • \(Window10\) 下没有虚拟机和双系统,被迫使用 \(Dev-C++\) ,中途想要对拍发现 ./可执行文件.exe 用不了,捣鼓了半天 \(cmd\)\(Power Shell\) 无果,无奈使用 \(VsCode\) 终端,但因为 \(VsCode\) 什么插件都没有实际执行的时候出了一堆奇奇怪怪的问题。
  • \(T1\) 不知道自己 \(n=2\) 的部分分挂在哪里了。

后记

  • 因原 \(5\) 道题目都声称之前见过或做过弱化版, \(huge\) 把整套题都换了,原来那套留给我们做练习题用。
posted @ 2025-02-21 06:42  hzoi_Shadow  阅读(294)  评论(5)    收藏  举报
扩大
缩小