8.28

06:12 Graph Problem With Small

无向图上的状压dp

学到了一些东西:

1.通过先枚举状态然后枚举起点终点来转移,这样你有的时候会发现一些可以省掉的枚举

2.利用bitset来转移,看代码:

void Dp(){
 int u=0;
 dp[1][0]=1;
 F(sta,0,(1<<n)-1){
  if(disj(sta,1<<u))continue;
  F(v,0,n-1){
   if(v==u||disj(sta,1<<v))continue;
   bitset<N>tmp=dp[sta^(1<<v)]&e[v];
   if(tmp.count()!=0)dp[sta][v]=1;
  }
 }
 F(s,0,(1<<n)-1){
  int t=(((1<<n)-1)-s)|1;
  F(v,0,n-1)
   if(dp[s][v])ans[v]|=dp[t];
 }
 
}

16:19 A Simple Task

这个也是的

  然后这题的trick:

1.为了防止环记录重复,我们钦定最小的那个点为环的起点。

  其次是注意一条边会被当做环记录,以及环会被正反两个方向统计,注意剪掉。

13:53 树上数颜色

树上启发式合并

  首先,考虑暴力,我们对一个点的子树完全遍历,然后统计答案再减去,防止对其他的统计有影响

这个有一个性质,就是最后的一个子树答案不用剪掉

  这个就是启发式合并复杂度正确的关键了

  对树进行轻重剖分,每次先统计轻子节点的答案,然后减掉,对重儿子就不用减去

轻儿子只有log个,重儿子只走一遍,复杂度就对了

  树上启发式合并就这了

15:48 点分树 | 震波

这个核工业代码

有几个代码实现上的关键点:

1.虚树上的点和实际上的点没有位置关系上的关联,所以说会有很多想当然上的问题

2.距离存在0,用BIT维护的时候要+1

3.每个节点都要开BIT,所以说空间会炸,需要基于vector的动态开点BIT.

4.注意两种BIT的空间的不同

然后是简要的做题思路

维护一颗基于淀粉质的虚树,显然树高是log的。

然后是求答案:

对于所有父子节点对​\(i\)\(i和fa[i]有答案是fa[i]的- i的\)

这个具体的看代码?

void upd(int x,int k){
    tr1[x].upd(0,k);
    for(int i=x;fa[i];i=fa[i]){
        tr1[fa[i]].upd(dist(fa[i],x),k);
        tr2[i].upd(dist(fa[i],x),k);
    }
}
int que(int x,int k){
    int ans=0;
    ans+=tr1[x].sum(k);
    for(int i=x;fa[i];i=fa[i]){
        int tmp=k-dist(fa[i],x);if(tmp<0)continue;
        ans+=tr1[fa[i]].sum(tmp);
        ans-=tr2[i].sum(tmp);
    }
    return ans;
}

18:28 大数

关键就是一个式子的转化:

\[\frac{sum[L]-sum[R+1]}{10^{n-R}} == 0(mod p) \]

这个就要分类讨论了:

1.p不能整除10,也就是说 $$sum[L]-sum[R+1]==0$$

那么就是 $$sum[L]==sum[R+1]$$,变成了一般的莫队计数

2.否则,​\(p==2 or 5\)​ 这也有很好的性质.​\(相当于是你可以直接根据最后一位推断能否整除\)
根据以下公式直接计算:

    F(i,1,n){
        if((s[i]-'0')%p==0)s1[i]++,s2[i]+=i;
        s1[i]+=s1[i-1];s2[i]+=s2[i-1];
    }
    m=rd();
    while(m--){
        int l=rd(),r=rd() ;
        int num=s1[r]-s1[l-1],sum=s2[r]-s2[l-1];
        cout<<sum-(l-1)*num<<'\n';
    }

至于为什么是这个式子就自己手推一下就好了.

posted @ 2023-08-29 16:02  ussumer  阅读(20)  评论(0)    收藏  举报