省选联测 32

铸币时刻了。别老惦记着你那 b 正解了。

光明

场上想到了长剖然后开桶打个 lazy 标记可以做到线性。然而手画了两下发现每次跑一段貌似得存以下这一段的标记等搜完子树再清标记。然而下场发现只要在当前节点先减掉然后搜轻子树再加上就行了。那我是 sb。

下场问了几个人发现场上以为是暴力的 \(O(n\log n)\) 做法(差不多就是题解那个长剖二分)能过。那我是真小丑。

#include <iostream>
#include <algorithm>
#include <cstdio>
#define int long long
using namespace std;
struct node{
    int v,next;
}edge[3000010];
int n,t,head[3000010];
long long k;
void add(int u,int v){
    edge[++t].v=v;edge[t].next=head[u];head[u]=t;
}
int dis[3000010],son[3000010],len[3000010],dep[3000010];
void dfs1(int x,int f){
    dep[x]=dep[f]+1;
    for(int i=head[x];i;i=edge[i].next){
        dfs1(edge[i].v,x);
        if(dis[son[x]]<dis[edge[i].v])son[x]=edge[i].v;
    }
    dis[x]=dis[son[x]]+1;
}
void dfs2(int x,int tp){
    len[x]=dep[x]-dep[tp]+1;
    if(son[x])dfs2(son[x],tp);
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=son[x])dfs2(edge[i].v,edge[i].v);
    }
}
int s[3000010],buf[3000010];
int *dp[3000010],*now=buf;
void dfs(int x){
    if(son[x]){
        dp[son[x]]=dp[x]+1;
        dfs(son[x]);
    }
    int mx=0;
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=son[x])mx=max(mx,dis[edge[i].v]);
    }
    for(int i=1;i<=mx;i++)s[dp[x][i]]-=len[x];
    dp[x][0]=1;
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=son[x]){
            dp[edge[i].v]=now;now+=dis[edge[i].v];
            dfs(edge[i].v);
            for(int j=1;j<=dis[edge[i].v];j++)dp[x][j]+=dp[edge[i].v][j-1];
        }
    }
    for(int i=0;i<=mx;i++)s[dp[x][i]]+=len[x];
}
signed main(){
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout);
    scanf("%lld%lld",&n,&k);
    for(int i=2;i<=n;i++){
        int f;scanf("%lld",&f);add(f,i);
    }
    dfs1(1,0);dfs2(1,1);
    dp[1]=now;now+=dis[1];
    dfs(1);
    long long ans=0;
    for(int i=n;i>=1;i--){
        long long ret=min(k,1ll*s[i]);
        ans+=1ll*ret*i;k-=ret;
    }
    printf("%lld\n",ans);
    return 0;
}

游戏

这题就是让你计数 \(m\) 种颜色染个连续段长度不超过 \(k\)\(n\) 长度纸带的方案数。场上套了个分式分解套了个复合提系数提不出来,白瞎三个小时。

一个显而易见的 dp 是设 \(dp_i\) 为到 \(i\) 的方案数,然后枚举段长可以得到

\[dp_i=(m-1)\sum_{j=1}^{k-1}dp_{i-j} \]

答案就是 \(\dfrac m{m-1}dp_n\)

正解是根据 \(k\) 大小平衡一下复杂度。对于 \(k\) 小的时候,直接上线性递推 \(O(k\log k\log n)\)。不知道出任意模数线性递推是个什么心态。

\(k\) 大的时候推一下式子。

首先答案的生成函数显然是

\[\begin{aligned} &\sum_{n=0}\left((m-1)\sum_{i=1}^{k-1}x^i\right)^n\\ =&\frac 1{1-(m-1)\frac {x-x^k}{1-x}}\\ =&\frac {1-x}{1-mx+(m-1)x^k} \end{aligned} \]

(场上好像用完全不同的方式得到了相同的结果然而嗯想分式分解了)

那上边那个 \(1-x\) 显然不用管。看看下边,这玩意第 \(n\) 项就是

\[\begin{aligned} &[x^n]\sum_{i=0}(mx+(1-m)x^k)^i\\ =&[x^n]\sum_{i=0}\sum_{j=0}^i\binom ij(1-m)^jm^{i-j}x^{jk+i-j}\\ =&\sum_{i=0}\binom{n-i(k-1)}i(1-m)^im^{n-ik} \end{aligned} \]

lucas 爆算即可。

代码没写完。不想写任意模线性递推。

皇后

\(n\) 皇后问题的一组解。参考邓老师的调整法。每次找到只被一个皇后覆盖的地方把那个皇后放过来,复杂度据说是 \(O(n^3)\)。然而他这个实测准不准也不是很好说。

posted @ 2023-02-14 16:19  gtm1514  阅读(17)  评论(0编辑  收藏  举报