bzoj 2152 聪聪可可

网友投稿 672 2022-10-05

bzoj 2152 聪聪可可

bzoj 2152 聪聪可可

​​‎

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 1 3 2 1 4 1 2 5 3 Sample Output 13/25 【样例说明】 13组点对分别是(1,1) (2,2) (2,3) (2,5) (3,2) (3,3) (3,4) (3,5) (4,3) (4,4) (5,2) (5,3) (5,5)。

数据规模】 对于100%的数据,n<=20000。 xtx学长课件里的题 写完搜题解才发现树形dp也可以搞 回来试一试x 点分: 找重心 然后算过重心的全部%3=0的点有多少个 然后参照之前写的点分治容斥一下即可 关于怎么计算这个%3==0的个数我被visjiao和icefox巨佬都被秒杀了 辣鸡蒟蒻elijahqi: sort快排然后扫一扫 visjiao&icefox:什么直接统计个数不就好 辣鸡蒟蒻elijahqi:那我0的个数就是我要的个数咯 visjiao:C(2,cnt[0]) 我Orz囧rz 我好菜啊qwq

#include#include#include#define N 22000#define inf 0x3f3f3f3fusing namespace std;inline char gc(){ static char now[1<<16],*S,*T; if (T==S) {T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;} return *S++;}inline int read(){ int x=0;char ch=gc(); while(ch<'0'||ch>'9') ch=gc(); while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc(); return x;}int f[N],size[N],sum,dis[N],num,n,root,ans,d[N],cnt[3],h[N];bool visit[N];struct node{ int x,y,z,next;}data[N<<1];inline void get_root(int x,int fa){ f[x]=0; for (int i=h[x];i;i=data[i].next){ int y=data[i].y;if (y==fa||visit[y]) continue; f[x]=max(f[x],size[y]);get_root(y,x); }f[x]=max(f[x],sum-size[x]); if(f[root]>f[x]) root=x;}inline void get_dis(int x,int fa){ dis[++num]=d[x]%3; for (int i=h[x];i;i=data[i].next){ int y=data[i].y,z=data[i].z; if (y==fa||visit[y]) continue;d[y]=d[x]+z;get_dis(y,x); }}inline int calc(int x,int cost){ num=0;d[x]=cost;get_dis(x,x);memset(cnt,0,sizeof(cnt)); for (int i=1;i<=num;++i) ++cnt[dis[i]];int tmp=0; tmp+=cnt[0]*(cnt[0]-1)>>1;tmp+=cnt[1]*cnt[2];return tmp;}inline void get_size(int x,int fa){ size[x]=1; for (int i=h[x];i;i=data[i].next){ int y=data[i].y;if (y==fa||visit[y]) continue; get_size(y,x);size[x]+=size[y]; }}inline void solve(int x){ visit[x]=1;get_size(x,0);ans+=calc(x,0); for (int i=h[x];i;i=data[i].next){ int y=data[i].y,z=data[i].z;if (visit[y]) continue; ans-=calc(y,z);sum=size[y];root=0;get_root(y,0);solve(root); }}inline int gcd(int x,int y){ if (y==0) return x;return gcd(y,x%y);}int main(){ freopen("bzoj2152.in","r",stdin); n=read(); for (int i=1;i

树形dp填坑ing:

设dp[i][j]表示第i位上 我现在走到这里需要花%3余j的代价才可以 那么我强行转移下就好我设tmp[j]表示到达x的有多少个 然后每次用新的子树中的个数*我现在已经有和3互补的个数 (类似联合权值的思想 然后暴力dp即可

#include#include#include#define N 22000#define inf 0x3f3f3f3fusing namespace std;inline char gc(){ static char now[1<<16],*S,*T; if (T==S) {T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;} return *S++;}inline int read(){ int x=0;char ch=gc(); while(ch<'0'||ch>'9') ch=gc(); while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc(); return x;}struct node{ int y,z,next;}data[N<<1];int dp[N][3],n,ans,h[N],fa[N],num;inline void dfs(int x){ dp[x][0]+=1;int tmp[3];memset(tmp,0,sizeof(tmp));tmp[0]++; for (int i=h[x];i;i=data[i].next){ int y=data[i].y,z=data[i].z;if (fa[x]==y) continue;fa[y]=x; dfs(y); for (int j=0;j<3;++j) { int dis=(3-((j+z)%3))%3; ans+=tmp[dis]*dp[y][j]; } for (int j=0;j<3;++j){ dp[x][(j+z)%3]+=dp[y][j];tmp[(j+z)%3]+=dp[y][j]; } }}inline int gcd(int x,int y){ if (y==0) return x;return gcd(y,x%y);}int main(){ freopen("bzoj2152.in","r",stdin); n=read(); for (int i=1;i

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:小程序中实现选择预览图片同时可以实现长按删除图片的代码(小程序自定义图片预览)
下一篇:微信小程序中如何自定义showmodal弹出框(附代码)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~