HDU 5723 A t 组样例 n个点m条边
然后m条无向边
a b w
求他的最小生成树的 花费
然后求 每2个点的花费的期望
先跑一个最小生成树
然后呢 要求期望 先要求出一个 总体花费 然后 /(n*(n-1)/2)
那么怎么求花费呢 比如说样例 1 - 2 - 3 - 4
1 2 3
用dfs 维护子树的点的数目
那么这条边的贡献 就是num[孩子] *(n-num[孩子]) *w(边)
上面 下面
最后结果
#include<stdio.h> #include<algorithm> #include<stdlib.h> #include<cstring> #include<string> #include<cmath> #include<vector> #include<queue> #include<map> #include<stack> using namespace std; #define ll __int64 #define MAXN 100010 #define inf 1000000000 #define mod 1000000007 struct edg { int fr,to,w,next; }edge[1000010],edg1[2000010]; int z[MAXN]; bool cmp(edg a,edg b) { return a.w<b.w; } int find1(int a) { if(z[a]==a) return a; else { int b=find1(z[a]); return z[a]=b; } } int cnt; int head[MAXN]; void add(int u,int v,int w) { edg1[cnt].to=v; edg1[cnt].w=w; edg1[cnt].next=head[u]; head[u]=cnt++; } int sz[MAXN]; double ans1; int n,m; void dfs(int u,int fa) { sz[u]=1; for(int i=head[u];i!=-1;i=edg1[i].next) { int v=edg1[i].to; if(v==fa) continue; // printf("%d ",v); dfs(v,u); sz[u]=sz[u]+sz[v]; ans1=ans1+ (double)sz[v]*(n-sz[v])*edg1[i].w; //printf("%d %lf ",v,ans1); } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) z[i]=i; for(int i=1;i<=m;i++) scanf("%d%d%d",&edge[i].fr,&edge[i].to,&edge[i].w); sort(edge+1,edge+m+1,cmp); ll ans=0; cnt=0; memset(head,-1,sizeof(head)); int c1=0; for(int i=1;i<=m;i++) { int fa,fb; fa=find1(edge[i].fr); fb=find1(edge[i].to); if(fa!=fb) { c1++; z[fa]=fb; ans+=edge[i].w; add(edge[i].fr,edge[i].to,edge[i].w); add(edge[i].to,edge[i].fr,edge[i].w); } if(c1==n-1) break; } printf("%I64d ",ans); ans1=0; dfs(1,0); printf("%.2lf ",ans1/n/(n-1)*2); } return 0; }
HDU 5724 B
t 个样例
n 行
然后n行
m m个数字
代表开始的位置
一次只能像右 走1个能跳过去 不能重叠 最多走到20
Alice 先走 他能营的话 YES否则N0
显然多行的话就是个尼姆博弈
那么一行呢
看代码
#include<stdio.h> #include<algorithm> #include<stdlib.h> #include<cstring> #include<string> #include<cmath> #include<vector> #include<queue> #include<map> #include<iterator> #include<stack> using namespace std; #define ll __int64 #define MAXN 100010 #define inf 1000000000 #define mod 1000000007 bool vis[25]; int sg[1<<21]; int get(int a) { memset(vis,0,sizeof(vis)); for(int i=20;i>=0;i--) { if(a&(1<<i)) // 第i 是1 { int t=a; for(int j=i-1;j>=0;j--) { if(!(a&(1<<j))) //走到0的 { t^=(1<<i)^(1<<j); //把i 这个1去掉 j 这个1加上 vis[sg[t]]=1; //这个位子能走到 break; } } } } for(int i=0;i<=20;i++) //最多能走到20种 所以.. if(!vis[i]) return i; } int main() { int t; scanf("%d",&t); for(int i=0;i<(1<<21);i++) //预处理出每个状态的sg sg[i]=get(i); while(t--) { int n; scanf("%d",&n); int ans=0; for(int i=1;i<=n;i++) { int m; scanf("%d",&m); int now=0; for(int j=1;j<=m;j++) { int a; scanf("%d",&a); now|=1<<(20-a); //这边每个就上去1 } ans ^=sg[now]; } if(ans==0) printf("NO "); else printf("YES "); } return 0; }
D hdu 5726
t 组样例 n 个数
M 个查询
问所有区间里能和这个区间gcd一样的数目 长度为1的也算
输出gcd和数目
显然先要线段树维护一下gcd
然后暴力统计一下到z[i]的gcd的数目 ans[a]=b 代表gcd为a的区间数目为b
m1 是到z[i] 的gcd数目 m2临时的 ans 结果
#include<stdio.h> #include<algorithm> #include<stdlib.h> #include<cstring> #include<string> #include<cmath> #include<vector> #include<queue> #include<map> #include<iterator> #include<stack> using namespace std; #define ll __int64 #define MAXN 100010 #define inf 1000000000 #define mod 1000000007 struct node { int l,r,w; }tree[MAXN<<2]; int z[MAXN]; int gcd(int a,int b) { return b?gcd(b,a%b):a; } void push_up(int a) { tree[a].w=gcd(tree[a<<1].w,tree[a<<1|1].w); } void Build(int l,int r,int a) { tree[a].l=l; tree[a].r=r; if(l==r) { tree[a].w=z[l]; return ; } int mid=(l+r)>>1; Build(l,mid,a<<1); Build(mid+1,r,a<<1|1); push_up(a); } int Ques(int l,int r,int l1,int r1,int a) { if(l1<=l&&r<=r1) { return tree[a].w; } int ans=0; int mid=(l+r)>>1; if(l1<=mid) ans = gcd(ans,Ques(l,mid,l1,r1,a<<1)); if(r1>mid) ans = gcd(ans,Ques(mid+1,r,l1,r1,a<<1|1)); return ans; } map<int,ll>ans,m1,m2; int main() { int t,ca; scanf("%d",&t); ca=1; while(t--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&z[i]); Build(1,n,1); printf("Case #%d: ",ca++); ans.clear(); m1.clear(); m2.clear(); m1[z[1]]++; ans[z[1]]++; for(int i=2;i<=n;i++) { int now=z[i]; m2[now]++; ans[now]++; for(map<int,ll>::iterator it=m1.begin();it!=m1.end();it++) { int g=gcd(now,it->first); m2[g]+=it->second; ans[g]+=it->second; } m1.clear(); for(map<int,ll>::iterator it=m2.begin();it!=m2.end();it++) { m1[it->first]=it->second; } m2.clear(); } int m; scanf("%d",&m); while(m--) { int l,r; scanf("%d%d",&l,&r); int tmp=Ques(1,n,l,r,1); printf("%d %I64d ",tmp,ans[tmp]); } } return 0; }