一个盒子里有n 个黑球和m 个白球。现在DZY每次随机从盒子里取走一个球,取了n+m 次后,刚好取完。DZY用这种奇怪的方法生成了一个随机的01串S[1?(n+m)] 。如果DZY第i 次取出的球是黑色的,那么S[i]=1 ,如果是白色的,那么S[i]=0 。 DZY现在想知道,‘01‘在S 串中出现的期望次数。
输入有多组测试数据。 (TestCase≤150 ) 每行两个整数,n ,m(1≤n,m≤12)
对于每个测试数据,输出一行答案,格式为p/q (p,q 互质)。
1 1 2 3
1/2 6/5
Case 1: S=‘01‘ or S=‘10‘, 所以期望次数 = 1/2 Case 2: S=‘00011‘ or S=‘00101‘ or S=‘00110‘ or S=‘01001‘ or S=‘01010‘ or S=‘01100‘ or S=‘10001‘ or S=‘10010‘ or S=‘10100‘ or S=‘11000‘, 所以期望次数 = (1+2+1+2+2+1+1+1+1+0)/10 = 12/10 = 6/5
排列组合。
一共有C(n+m,n)种排列。
01出现的次数:枚举01的位置然后计算其他位置的摆放方案数(n+m-1)*C(n+m-2,n-1)
期望(n+m-1)*C(n+m-2,n-1)/C(n+m,n)=(n*m)/(n+m)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; int main() { int n,m; while (scanf("%d%d",&n,&m)!=EOF) { int k=__gcd(n*m,n+m); cout<<n*m/k<<"/"<<(n+m)/k<<endl; } return 0; }
一张有向图的拓扑序列是图中点的一个排列,满足对于图中的每条有向边(u→v) 从u 到v ,都满足u 在排列中出现在v 之前。 现在,DZY有一张有向无环图(DAG)。你要在最多删去k 条边之后,求出字典序最大的拓扑序列。
输入有多组数据。 (TestCase≤5 ) 第一行,三个正整数n,m,k(1≤n,m≤105,0≤k≤m) . 接下来m 行,每行两个正整数u,v(u≠v,1≤u,v≤n) , 代表一条有向边(u→v) .
对于每组测试数据,输出一行字典序最大的拓扑序列。
5 5 2 1 2 4 5 2 4 3 4 2 3 3 2 0 1 2 1 3
5 3 1 2 4 1 3 2
数据1. 删除(2->3),(4->5)两条边,可以得到字典序最大的拓扑序列:(5,3,1,2,4).
(思路并不难的一道题,可是我在结束的前15分钟才想出来正解。。写出来了没调对。。)
首先计算出每个点的度数。
使拓扑序最大的数字就是当前度数<=k的最大数字,k-=他的度数,他所连得点度数减1。
然后重复这个过程。
问题就变成了查找<=k的最大数字,在线段树中维护区间最小值,直接二分就可以了。
修改的复杂度是O(mlogn),查询的复杂度是O(nlogn),总复杂度O((m+n)logn)
注意:此题不写读入优化就TLE了。。
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cmath> #define inf 0x3f3f3f3f using namespace std; int cnt,tot,h[150005],d[150005],n,m,k; struct edge { int y,ne; }e[150005]; struct Segtree { int l,r,m; }a[500000]; void read(int &tmp) { tmp=0; int fu=1; char ch=getchar(); for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') fu=-1; for (;ch>='0'&&ch<='9';ch=getchar()) tmp=tmp*10+ch-'0'; tmp*=fu; } void Addedge(int x,int y) { e[++tot].y=y; e[tot].ne=h[x]; h[x]=tot; d[y]++; } void P(int x) { if (a[x<<1].m<a[(x<<1)+1].m) a[x].m=a[x<<1].m; else a[x].m=a[(x<<1)+1].m; } void Build(int x,int l,int r) { a[x].l=l,a[x].r=r; if (l==r) { a[x].m=d[l]; return; } int m=(l+r)>>1; Build(x<<1,l,m); Build((x<<1)+1,m+1,r); P(x); } int Find(int x,int k) { if (a[x].l==a[x].r) return a[x].l; if (a[(x<<1)+1].m<=k) return Find((x<<1)+1,k); return Find(x<<1,k); } void M(int x,int y,int k) { if (a[x].l==a[x].r) { a[x].m+=k; return; } int m=(a[x].l+a[x].r)>>1; if (y<=m) M(x<<1,y,k); else M((x<<1)+1,y,k); P(x); } int main() { while (scanf("%d%d%d",&n,&m,&k)!=EOF) { tot=0; for (int i=1;i<=n;i++) d[i]=0,h[i]=0; int x,y; for (int i=1;i<=m;i++) { read(x),read(y); Addedge(x,y); } Build(1,1,n); for (int i=1;i<=n;i++) { x=Find(1,k); k-=d[x]; M(1,x,inf); d[x]=inf; if (i==1) printf("%d",x); else printf(" %d",x); for (int j=h[x];j;j=e[j].ne) if (d[e[j].y]!=inf) M(1,e[j].y,-1),d[e[j].y]--; } printf("\n"); } return 0; }
原文地址:http://blog.csdn.net/regina8023/article/details/44840689