模拟赛T1
题面
赛时糖了,写了个会t的状压还不会处理下界
题面中的限制可以转为:
对于任意合法集合
1.必须包含n的每个质因数的最大次方
2.至少出现一对不同质因数
严肃发现质因子数目比logn还要小的多,可以爆搜
直接算有点难统计,考虑容斥,把所有方案算出来再去掉不合法方案
于是就拥有了一份比std简洁许多的代码,时间复杂度,k为质因数个数
点击查看代码
void dfs(int x,ll s,ll k) { //s为有多少质因子组合成的因数可选,k为容斥系数if(x>m) {add(ans,qm(2,s)-1,k);//要把全不选的情况减掉return ;} dfs(x+1,s*a[x]%M,k);dfs(x+1,s*(a[x]-1)%M,(M+M-k-k)%M); //所有方案和不合法方案if(a[x]>2) dfs(x+1,s*(a[x]-2)%M,k); //多减的要补回来
}
void solve() {freopen("set.in","r",stdin);freopen("set.out","w",stdout);cin>>n;for(ll i=2;i*i<=n;i++) {if(n%i==0) {a[++m]=1; //初值设成1方便计算while(n%i==0) n/=i,a[m]++;}} if(n>1) a[++m]=2;dfs(1,1,1); printf("%lld",ans%M);
}
CF1916E
数据结构糖题
考虑枚举每个点,计算它作为lca时的贡献,自然地,我们需要维护每个点子树里的点到子树跟的路径上有多少不同的颜色,对于单个点的答案,查询其儿子子树中的最大值与次大值再相乘
怎么维护子树中的点到当前点路径上的颜色数呢?我们先考虑链的情况,在从下往上跳的过程中,跳到新点就把下面的点答案全加一,但如果有的点先前往上跳时就遇到了与当前同色的点,那么就加多了,此时我们发现,与当前点颜色相同且距离最近的点下面的点答案都会加多,那么我们需要维护每个点离它最近的同色点,在更新答案时把那个点下面的点答案减一就好了!现在考虑扩展到树,我们发现对于当前点每个儿子的子树内,都要维护最近的同色点,这样我们就成功解决了同色算重的问题,现在我们需要对树上点的答案进行区间加减查询,用线段树就可以维护
核心代码
处理同色点部分
点击查看代码
void dfs(int x) {dfn[x]=++ct;int idx=c[w[x]];if(c[w[x]]) e[c[w[x]]].pb(x);c[w[x]]=x;for(auto v:a[x]) {c[w[x]]=x; dfs(v); } dr[x]=ct; c[w[x]]=idx;
}
维护答案部分
点击查看代码
void dfs1(int x) {for(auto v:a[x]) dfs1(v);T.upd(1,dfn[x],dr[x],1,n,1);for(auto v:e[x]) T.upd(1,dfn[v],dr[v],1,n,-1);ll m1=1,m2=1;for(auto v:a[x]) {int s=T.qry(1,dfn[v],dr[v],1,n);if(s>m1) m2=max(m2,m1),m1=s;else if(s>m2) m2=s; } ans=max(ans,m1*m2);
}