bzoj

bzoj 2152 聪聪可可(点分治模板)

*爱你&永不变心* 提交于 2019-12-20 05:05:19
2152: 聪聪可可 Time Limit: 3 Sec Memory Limit: 259 MB Submit: 3194 Solved: 1647 [ Submit ][ Status ][ Discuss ] Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是3的倍数,则判聪聪赢,否则可可赢。聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。 Input 输入的第1行包含1个正整数n。后面n-1行,每行3个整数x、y、w,表示x号点和y号点之间有一条边,上面的数是w。 Output 以即约分数形式输出这个概率(即“a/b”的形式,其中a和b必须互质。如果概率为1,输出“1/1”)。 Sample Input 5 1 2 1

BZOJ 1010 [玩具装箱 toy]

旧街凉风 提交于 2019-12-14 15:15:47
题面 题意   将一个序列 \(\{a_n\}\) 分割成若干段,令第 \(i\) 段的的和为 \(s_i\) ,则代价为 \(\sum(s_i-L)^2\) ,求最小代价。 题解   令 \(sum_i=\sum_{j=1}^ia_j\) ,用 \(dp_i\) 代表将前 \(i\) 项分割成若干段的最小代价,那么根据定义: \[ \begin{aligned} dp_i&=\min_{j=0}^{i-1}\{dp_j+(sum_i-sum_j-L)^2\}\\ &=\min_{j=0}^{i-1}\{dp_j+sum_i^2-2sum_i(sum_j+L))+(sum_j+L)^2\}\\ &=sum_i^2+\min_{j=0}^{i-1}\{(-2sum_j+L)sum_i+(dp_j+(sum_j+L)^2)\}\\ \end{aligned} \]   化成最后一行的形式之后,令 \(f_i(x)=(-2sum_i+L)x+(dp_i+(sum_i+L)^2)\) ,则 \(dp_i=sum_i^2+\min_{j=0}^{i-1}f_j(sum_i)\) 。由于 \(f_i(x)\) 是一次函数,并且斜率 \(k_i<k_j(i<j)\) ,所以可以用队列维护一个由 \(l:f_i(x)\) 构成的上凸壳,每次先在上凸壳中查找 \(\min_{j=0}^{i-1}f

BZOJ 3261: 最大异或和 可持久化trie

久未见 提交于 2019-12-09 04:05:55
模板题,刷点数据结构 ~ code: #include <bits/stdc++.h> #define N 600009 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int rt[N],sum[N],tot; struct node { int ch[2],cnt; }t[N*28]; void insert(int a,int b,int len,int num) { if(len<0) return; int o=(num>>len)&1; t[b].ch[o^1]=t[a].ch[o^1]; t[b].ch[o]=++tot; t[t[b].ch[o]].cnt=t[t[a].ch[o]].cnt+1; insert(t[a].ch[o],t[b].ch[o],len-1,num); } int query(int l,int r,int len,int x) { if(len<0) return 0; int o=(x>>len)&1; if(t[t[r].ch[o^1]].cnt>t[t[l].ch[o^1]].cnt) { return (1<<len)+query(t[l].ch[o^1],t[r].ch[o^1],len-1,x); } else { return query(t[l

BZOJ 3527 FFT

筅森魡賤 提交于 2019-12-08 18:46:31
首先我们知道 \(\displaystyle E_j=\sum_{i<j}\frac{q_i}{(i-j)^2}-\sum_{i>j}\frac{q_i}{(i-j)^2}\) , 设 \(\displaystyle g[i]=\frac{1}{i^2}\) ,因为 \(g\) 是偶函数,所以 \(\displaystyle E_j=\sum_{i=0}^{j-1} q_i g[j-i]-\sum_{i=j+1}^n q_ig[j-i]\) 。 前面这东西很明显就是卷积,处理后面就要发挥人类智慧了,将 \(q_i\) 翻转成新数组 \(q_i'\) ,原来的式子就成了 \(\displaystyle E_j=\sum_{i=0}^{j-1} q_i g[j-i]-\sum_{i=0}^{j-1} q_i'g[j-i]\) , 后面这东西也变成卷积啦,用FFT处理一下就ok啦。 时间复杂度O(n log n). #include<iostream> #include<cstdio> #include<cmath> #define DB double using namespace std; int n,lim=1,tmp; const DB PI=acos(-1); const int N=400010; struct lmaginary { DB x,y; lmaginary

BZOJ 2132 圈地计划

为君一笑 提交于 2019-12-08 16:38:28
题目 传送门 分析: 首先A和B2选1就是一组矛盾关系 然后相邻的两个格子选相同的也是一种矛盾 我们可以把格子染成黑白颜色,像国际象棋棋盘那样 对于黑格子,与S连容量为A的边,与T连容量为B的边 对于白格子,与S连容量为B的边,与T连容量为A的边 然后相邻格子,连容量为两个格子C之和的边 考虑正确性 同一个格子,A和B必须割一个 对于相邻格子,选相同和额外收益必须割一个 没有问题 #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #define maxt 10005 #define maxn 105 #define INF 0x3f3f3f3f using namespace std; inline int getint() { int num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); return num*flag; } int n,m,S,T; int fir[maxt],nxt[20*maxt],to[20*maxt],cap[20*maxt],cnt; int a

BZOJ 3451: Tyvj1953 Normal 点分治+FFT

自作多情 提交于 2019-12-06 04:11:15
根据期望的线性性,我们算出每个点期望被计算次数,然后进行累加. 考虑点 $x$ 对点 $y$ 产生了贡献,那么说明 $(x,y)$ 之间的点中 $x$ 是第一个被删除的. 这个期望就是 $\frac{1}{dis(x,y)+1}$,所以我们只需求 $\sum_{i=1}^{n}\sum_{j=1}^{n}\frac{1}{dis(i,j)+1}$ 即可. 然后这个直接求是求不出来的,所以需要用点分治+FFT来算树上每种距离都出现了多少次. code: #include <bits/stdc++.h> using namespace std; #define N 500003 #define ll long long #define setIO(s) freopen(s".in","r",stdin) const double pi=acos(-1); ll ans[N]; int edges,root,sn,n,mxdep; int size[N],mx[N],hd[N],to[N<<1],nex[N<<1],vis[N]; inline void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } struct cpx { double x,y; cpx(double a=0,double b=0) {

BZOJ 5338: [TJOI2018]xor 可持久化trie+dfs序

元气小坏坏 提交于 2019-12-05 16:59:56
强行把序列问题放树上,好无聊啊~ code: #include <bits/stdc++.h> #define N 200005 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int tot,edges,tim; int cnt[N*33],ch[N*33][2],tree[N],seq[N],val[N],ba[N]; int fa[N],son[N],size[N],top[N],dep[N],hd[N],to[N<<1],nex[N<<1],dfn[N],ed[N]; inline void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } void insert(int pre,int &x,int v) { int now=x=++tot; for(int i=30;i>=0;--i) { int o=((v>>i)&1); ch[now][o^1]=ch[pre][o^1]; ch[now][o]=++tot; pre=ch[pre][o]; now=tot; cnt[now]=cnt[pre]+1; } } void dfs1(int u,int ff) { fa[u]=ff,dep[u]=dep[ff]+1

BZOJ 3261: 最大异或和 可持久化trie

蓝咒 提交于 2019-12-05 16:23:43
模板题,刷点数据结构 ~ code: #include <bits/stdc++.h> #define N 600009 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int rt[N],sum[N],tot; struct node { int ch[2],cnt; }t[N*28]; void insert(int a,int b,int len,int num) { if(len<0) return; int o=(num>>len)&1; t[b].ch[o^1]=t[a].ch[o^1]; t[b].ch[o]=++tot; t[t[b].ch[o]].cnt=t[t[a].ch[o]].cnt+1; insert(t[a].ch[o],t[b].ch[o],len-1,num); } int query(int l,int r,int len,int x) { if(len<0) return 0; int o=(x>>len)&1; if(t[t[r].ch[o^1]].cnt>t[t[l].ch[o^1]].cnt) { return (1<<len)+query(t[l].ch[o^1],t[r].ch[o^1],len-1,x); } else { return query(t[l

[bzoj 3732] Network (Kruskal重构树)

社会主义新天地 提交于 2019-12-05 14:58:55
https://blog.csdn.net/niiick/article/details/81952126 https://www.cnblogs.com/ZegWe/p/6243883.html Kruskal重构树—性质 1.是一个小/大根堆(由建树时边权的排序方式决定) 2.LCA(u,v)的权值是 原图 u到v路径上最大/小边权的最小/大值(由建树时边权的排序方式决定) Kruskal重构树—建树 模仿kruskal的过程 先将边权排序 (排序方式决定何种性质接下来说明) 依次遍历每条边 若改变连接的两个节点u和v 不在一个并查集内 就新建一个结点node 该点点权为这条边的边权 找到u,v所在并查集的根ui,vi u_i,v_iu i ​ ,v i ​ 连边(node,ui)(node,vi) (node,u_i)(node,v_i)(node,u i ​ )(node,v i ​ ) 并更新并查集fa[ui]=node,fa[vi]=node fa[u_i]=node,fa[v_i]=nodefa[u i ​ ]=node,fa[v i ​ ]=node 遍历完原图所有边后 我们建出来的必定是一棵树 也就是我们要的kruskal重构树 注意这棵树是以最后新建的结点为根的有根树 若原图不连通,即建出的是一个森林 那么就遍历每个节点,找到其并查集的根作为其所在树的根 1