纪中寒假集训1.18总结
2018-01-18 22:29
411 查看
qaq题目好难啊
不过也还是可以水分的
今天做的THUWC模拟,简要放个题解:
1≤n≤105,1≤k≤5
这里k很小,所以可以考虑特殊讨论
k=1谁都会
考虑一种比较特殊的情况,就是这个所构成的群是一个循环群,大概就是一个{e,g,g2,g3,g4⋯}的样子
很明显由于群的封闭性,考虑其中某一个g,如果g≠e,那么g2≠g,然后进一步地可以产生后面的那些置换
当然我们还需要的是进一步产生的这些置换不相同,那么就构成了一个循环群,循环群的阶显然就是循环节的长度+1(算上单位元)
考虑如果k是质数(k=2,3,5)的时候,只能是考虑相应阶=k的情况,这个可以通过搞出生成元之后DP解决
但是如果k=4就复杂得多了,首先同构于循环群的情况很容易解决,只是要考虑1,2,4的情况
然后还有一种情况,就是对于某个{e,i,j,k}满足i2=j2=k2=e,而且ij=k,ik=j,kj=i,很像四元数,而且置换的性质也差不多是牺牲了交换律的
然后考虑相当于依次地考虑i,j,k,然后再乘回来6(3!)就可以了
先枚举一波i,因为i2=e,那么考虑枚举i里面长度2的循环,设有a个,剩下来的长度为1的循环有n−2a个,下面问题在于怎么继续把这些轮换放到j和k里面去
下面引用原题解:
这 a 个大小为 2 的轮换在 j 和 k 中有两种组合方式.
第一种是两两组合, 比如说 i 中的两个轮换 (a b)(c d) 在 j 和 k 中分别对应 (a d)(b c) 和
(a c)(b d), 这样的话, 它对答案的贡献就是 2.
第二种是单个组合, 比如说 i 中的 (a b) 在 j 和 k 中分别对应 (a b) 和 (a)(b), 这样的贡献
仍然是 2.
因此这一部分的每一种方案的贡献是 2, 而所有方案的总贡献就求个和就可以了.
剩下的 n − 2a 个大小为 1 的轮换也有两种情况.
第一种是单个组合, 比如说 i 中的 (a) 在 j 和 k 中都是 (a), 这样的贡献是 1.
第二种是两两组合, 比如说 i 中的 (a)(b) 在 j 和 k 都是 (a b), 这样的贡献也是 1.
因此这一部分的贡献是所有轮换都不大于 2 的置换个数.
最后再乘一个排列数, 枚举哪些位置是大小为 1 的轮换就可以了.
其中xi,yi,zi≤77,n≤777777
先考虑一维的差的时候可以怎么做来推广下,我们可以考虑让A1(x)=∑i=1nxai,然后搞一波A1(x)A1(1x),对应系数就完成了生成函数的计数
我们如法炮制搞一个A3(x,y,z)=∑i=1nxaiybizci,然后同样乘起来就好辣!
然后来一个三维FFT就解决了我们可以考虑利用类似进制转换的思路,考虑把xaiybizci变成x(aibici)m就可以了
但是如果有负数怎么办?FFT怎么搞负指数?多项式求逆
直接加上个m就可以了,变成2m进制
然后这时再卡卡常就写过了(据说6s变2s?),两次FFT的做法不会……
先考虑这题有什么奇怪的暴力做法,我们考虑对于一个点i的子树里面,所有经过i的路径要么以i为一个端点要么在不同的两棵子树里。我们设f(x)表示以x为根的子树里的所有答案,w(x)表示这个点到随便制定的一个根节点的路径上点权和,那么如果我们直接对当前节点的几个孩子搞一下以当前点为端点的答案,然后再暴力合并子树的答案,两两枚举看看有没有超过限制(这个限制的判定可以借助w解决)
然后怎么优化呢?利用dsu on trees技术,就是启发式合并,先重链剖分,然后节点按照大小排个序就可以了
不过也还是可以水分的
今天做的THUWC模拟,简要放个题解:
【A:群】
题意
求对于大小为n的置换对于“复合”这一运算a∘b所构成的阶为k的群的个数1≤n≤105,1≤k≤5
分析
最近怎么总是遇到群论的题目……之前loj上碰到两道,今天又来……这里k很小,所以可以考虑特殊讨论
k=1谁都会
考虑一种比较特殊的情况,就是这个所构成的群是一个循环群,大概就是一个{e,g,g2,g3,g4⋯}的样子
很明显由于群的封闭性,考虑其中某一个g,如果g≠e,那么g2≠g,然后进一步地可以产生后面的那些置换
当然我们还需要的是进一步产生的这些置换不相同,那么就构成了一个循环群,循环群的阶显然就是循环节的长度+1(算上单位元)
考虑如果k是质数(k=2,3,5)的时候,只能是考虑相应阶=k的情况,这个可以通过搞出生成元之后DP解决
但是如果k=4就复杂得多了,首先同构于循环群的情况很容易解决,只是要考虑1,2,4的情况
然后还有一种情况,就是对于某个{e,i,j,k}满足i2=j2=k2=e,而且ij=k,ik=j,kj=i,很像四元数,而且置换的性质也差不多是牺牲了交换律的
然后考虑相当于依次地考虑i,j,k,然后再乘回来6(3!)就可以了
先枚举一波i,因为i2=e,那么考虑枚举i里面长度2的循环,设有a个,剩下来的长度为1的循环有n−2a个,下面问题在于怎么继续把这些轮换放到j和k里面去
下面引用原题解:
这 a 个大小为 2 的轮换在 j 和 k 中有两种组合方式.
第一种是两两组合, 比如说 i 中的两个轮换 (a b)(c d) 在 j 和 k 中分别对应 (a d)(b c) 和
(a c)(b d), 这样的话, 它对答案的贡献就是 2.
第二种是单个组合, 比如说 i 中的 (a b) 在 j 和 k 中分别对应 (a b) 和 (a)(b), 这样的贡献
仍然是 2.
因此这一部分的每一种方案的贡献是 2, 而所有方案的总贡献就求个和就可以了.
剩下的 n − 2a 个大小为 1 的轮换也有两种情况.
第一种是单个组合, 比如说 i 中的 (a) 在 j 和 k 中都是 (a), 这样的贡献是 1.
第二种是两两组合, 比如说 i 中的 (a)(b) 在 j 和 k 都是 (a b), 这样的贡献也是 1.
因此这一部分的贡献是所有轮换都不大于 2 的置换个数.
最后再乘一个排列数, 枚举哪些位置是大小为 1 的轮换就可以了.
【B:几何题】
题意
求∑i≠j|a(xi−xj)+b(yi−yj)+c(zi−zj)+d|n(n−1)(xi−xj)4+(yi−yj)4−−−−−−−−−−−−−−−−−√+(zi−zj)4其中xi,yi,zi≤77,n≤777777
分析
考虑利用数论函数变形的时候的常用套路,枚举这里三个维度上坐标的差,那么我们现在要求的实际上就是统计相应的坐标差的时候的方案数先考虑一维的差的时候可以怎么做来推广下,我们可以考虑让A1(x)=∑i=1nxai,然后搞一波A1(x)A1(1x),对应系数就完成了生成函数的计数
我们如法炮制搞一个A3(x,y,z)=∑i=1nxaiybizci,然后同样乘起来就好辣!
然后来一个三维FFT就解决了我们可以考虑利用类似进制转换的思路,考虑把xaiybizci变成x(aibici)m就可以了
但是如果有负数怎么办?FFT怎么搞负指数?多项式求逆
直接加上个m就可以了,变成2m进制
然后这时再卡卡常就写过了(据说6s变2s?),两次FFT的做法不会……
【C:树】
题意
给定一棵无根树,每个点上有个权值,问将树全部剖分成路径,使得路径上的点权和为正数的方案数分析
好久没写过超过110行的代码了……然后已经3.5K了……不过好像还是挺短的先考虑这题有什么奇怪的暴力做法,我们考虑对于一个点i的子树里面,所有经过i的路径要么以i为一个端点要么在不同的两棵子树里。我们设f(x)表示以x为根的子树里的所有答案,w(x)表示这个点到随便制定的一个根节点的路径上点权和,那么如果我们直接对当前节点的几个孩子搞一下以当前点为端点的答案,然后再暴力合并子树的答案,两两枚举看看有没有超过限制(这个限制的判定可以借助w解决)
然后怎么优化呢?利用dsu on trees技术,就是启发式合并,先重链剖分,然后节点按照大小排个序就可以了
代码
# include <algorithm> # include <cstring> # include <utility> # include <cstdio> # define inf 1000000000 # define mod 1000000007 # define N 100005 # define ms(x) (x>=mod?x-mod:x) # define mkp(x,y) make_pair(x,y) # define fi first # define se second # define mem(x,v) memset(x,v,sizeof(v)) using namespace std; typedef long long LL; struct edge{ int to,nxt; } e[N+N]; int cnt; int last ; struct node{ int tag,l,r,s; } t[N*40]; int sz; int n; int pre ,suf ; int val ; int tim,l ,r ; int siz ,son ,rt; int f ; pair<int,int> a ; int as; inline int read(){ int x=0,f=1; char c; for (c=getchar();c < '0' || c >'9';c=getchar()) if (c == '-') f=-1; for ( ;c>='0' && c<='9';c=getchar()) x=x*10+c-'0'; return x*f; } inline void addedge(int u,int v){ e[++cnt].to=v; e[cnt].nxt=last[u]; last[u]=cnt; e[++cnt].to=u; e[cnt].nxt=last[v]; last[v]=cnt; } inline bool cmp(int x,int y){ return siz[x]>siz[y]; } void dfs(int x,int fa){ val[x]+=val[fa]; siz[x]=1; for (int i=last[x];i;i=e[i].nxt){ if (e[i].to == fa) continue; dfs(e[i].to,x); siz[x]+=siz[e[i].to]; } l[x]=r[x]=tim+1; for (int i=last[x];i;i=e[i].nxt) if (e[i].to!=fa) son[++r[x]]=e[i].to; ++r[x]; tim=r[x]; sort(son+l[x]+1,son+r[x],cmp); //dsu on trees } inline int newnode(){ sz++; t[sz].tag=1; t[sz].l=t[sz].r=t[sz].s=0; return sz; } inline void pushdown(int d){ if (t[d].tag == 1) return; int w=t[d].tag,x;t[d].tag=1; x=t[d].l; if (x) t[x].tag=(LL)t[x].tag*w%mod,t[x].s=(LL)t[x].s*w%mod; x=t[d].r; if (x) t[x].tag=(LL)t[x].tag*w%mod,t[x].s=(LL)t[x].s*w%mod; } void ins(int& d,int l,int r,int x,int y){ if (!d) d=newnode(); if (l<r) pushdown(d); t[d].s=ms(t[d].s+y); if (l == r) return; int mid=((LL)l+(LL)r)>>1; if (x <= mid) ins(t[d].l,l,mid,x,y); else ins(t[d].r,mid+1,r,x,y); } int query(int d,int l,int r,int x,int y){ if (!d) return 0; if (l<r) pushdown(d); if (l==x && r==y) return t[d].s; int mid=((LL)l+(LL)r) >> 1,ans; if (y <= mid) ans+=query(t[d].l,l,mid,x,y); if (x > mid) ans+=query(t[d].r,mid+1,r,x,y); return ms(ans); } inline void get(int x,int fa,int s){ a[++as]=mkp(val[x],(LL)s*pre[r[x]-1]%mod); for (int i=l[x]+1;i<r[x];++i) get(son[i],x,(LL)s*pre[i-1]%mod*suf[i+1]%mod); } void dp(int x,int fa){ for (int i=l[x]+2;i<r[x];i++) dp(son[i],x),sz=0,rt=newnode(); if (l[x]+1<r[x]) dp(son[l[x]+1],x); pre[l[x]]=suf[r[x]]=1; for (int i=l[x]+1;i<r[x];++i) pre[i]=(LL)pre[i-1]*f[son[i]]%mod; for (int i=r[x]-1;i>l[x];--i) suf[i]=(LL)suf[i+1]*f[son[i]]%mod; if (val[x]-val[fa]>=0) f[x]=ms(f[x]+pre[r[x]-1]); f[x]=ms(f[x]+((LL)suf[l[x]+2]*query(rt,0,inf+inf,val[fa]+inf,inf+inf))%mod); for (int i=l[x]+2;i<r[x];++i){ as=0; get(son[i],x,1); for (int j=1;j<=as;++j){ if (a[j].fi-val[fa]>=0) f[x]=ms(f[x]+((LL)a[j].se*pre[i-1]%mod*suf[i+1]%mod)%mod); f[x]=ms(f[x]+(LL)a[j].se*suf[i+1]%mod*query(rt,0,inf+inf,val[x]+val[fa]-a[j].fi+inf,inf+inf)%mod); } t[rt].tag=(LL)t[rt].tag*f[son[i]]%mod; t[rt].s=(LL)t[rt].s*f[son[i]]%mod; for (int j=1;j<=as;++j) ins(rt,0,inf+inf,a[j].fi+inf,(LL)a[j].se*pre[i-1]%mod); } ins(rt,0,inf+inf,val[x]+inf,pre[r[x]-1]); } int main(){ freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); n=read(); for (int i=1;i<=n;++i) val[i]=read(); for (int i=1; i<n;++i){ int x=read(),y=read(); addedge(x,y); } dfs(1,0); sz=0; rt=newnode(); dp(1,0); printf("%d\n",f[1]); return 0; }
相关文章推荐
- 纪中集训18.01.19 多项式总结
- 寒假集训重要内容总结
- 寒假10days集训总结
- 2018寒假福州集训大总结
- (吐槽)寒假集训总结
- 寒假集训题总结1
- 2018寒假福建集训2.5~2.6两日博客总结
- 纪中集训总结 && 新学期目标
- 2018寒假集训总结第一节结构体
- 寒假集训总结
- 2018寒假福州集训大总结
- 2018寒假集训+补题总结
- 2.4-2.9 寒假集训总结 MVC 架构 框架
- 在成都七中的寒假信息竞赛集训总结
- 2.4-2.9 寒假集训总结 MVC 架构 框架
- ACM寒假集训部分题目总结
- 2018寒假福建集训2.9~2.10两日博客总结
- 寒假Java知识点总结
- 13暑假集训#8 总结
- 在寒假的学习总结和一些个人建议