Bestcoder #35
2015-03-29 00:12:33
总结:这场的状态和前两场一样糟糕... (话说自从bc发钱以来,参赛者实力高了一个档次...)
和前几场一样,第一题总是被卡... 不过后来沉下心耐心地搞掉了第二题...
A题:方法一:暴力打表 / 打表找规律。方法二:数学搞之,贴一下题解:
考虑期望的可加性。第i(1≤i<n+m)个位置上出现0
第i+1个位置上出现1的概率是m/(n+m)×n/(n+m−1),那么答案自然就是∑i=1,(n+m−1)m/(n+m)×n/(n+m−1)=nm/(n+m)
(1)规律/数学:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 25 int n,m; 26 27 int Gcd(int a,int b){ 28 while(a > 0 && b > 0){ 29 if(a > b) a %= b; 30 else b %= a; 31 } 32 return a + b; 33 } 34 35 int main(){ 36 while(scanf("%d%d",&n,&m) != EOF){ 37 int g = Gcd(n * m,n + m); 38 printf("%d/%d\n",n * m / g,(n + m) / g); 39 } 40 return 0; 41 }
(2)打表:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 25 string ans[200] = { 26 "", 27 "1/2", 28 "2/3", 29 "3/4", 30 "4/5", 31 "5/6", 32 "6/7", 33 "7/8", 34 "8/9", 35 "9/10", 36 "10/11", 37 "11/12", 38 "12/13", 39 "2/3", 40 "1/1", 41 "6/5", 42 "4/3", 43 "10/7", 44 "3/2", 45 "14/9", 46 "8/5", 47 "18/11", 48 "5/3", 49 "22/13", 50 "12/7", 51 "3/4", 52 "6/5", 53 "3/2", 54 "12/7", 55 "15/8", 56 "2/1", 57 "21/10", 58 "24/11", 59 "9/4", 60 "30/13", 61 "33/14", 62 "12/5", 63 "4/5", 64 "4/3", 65 "12/7", 66 "2/1", 67 "20/9", 68 "12/5", 69 "28/11", 70 "8/3", 71 "36/13", 72 "20/7", 73 "44/15", 74 "3/1", 75 "5/6", 76 "10/7", 77 "15/8", 78 "20/9", 79 "5/2", 80 "30/11", 81 "35/12", 82 "40/13", 83 "45/14", 84 "10/3", 85 "55/16", 86 "60/17", 87 "6/7", 88 "3/2", 89 "2/1", 90 "12/5", 91 "30/11", 92 "3/1", 93 "42/13", 94 "24/7", 95 "18/5", 96 "15/4", 97 "66/17", 98 "4/1", 99 "7/8", 100 "14/9", 101 "21/10", 102 "28/11", 103 "35/12", 104 "42/13", 105 "7/2", 106 "56/15", 107 "63/16", 108 "70/17", 109 "77/18", 110 "84/19", 111 "8/9", 112 "8/5", 113 "24/11", 114 "8/3", 115 "40/13", 116 "24/7", 117 "56/15", 118 "4/1", 119 "72/17", 120 "40/9", 121 "88/19", 122 "24/5", 123 "9/10", 124 "18/11", 125 "9/4", 126 "36/13", 127 "45/14", 128 "18/5", 129 "63/16", 130 "72/17", 131 "9/2", 132 "90/19", 133 "99/20", 134 "36/7", 135 "10/11", 136 "5/3", 137 "30/13", 138 "20/7", 139 "10/3", 140 "15/4", 141 "70/17", 142 "40/9", 143 "90/19", 144 "5/1", 145 "110/21", 146 "60/11", 147 "11/12", 148 "22/13", 149 "33/14", 150 "44/15", 151 "55/16", 152 "66/17", 153 "77/18", 154 "88/19", 155 "99/20", 156 "110/21", 157 "11/2", 158 "132/23", 159 "12/13", 160 "12/7", 161 "12/5", 162 "3/1", 163 "60/17", 164 "4/1", 165 "84/19", 166 "24/5", 167 "36/7", 168 "60/11", 169 "132/23", 170 "6/1" 171 }; 172 173 int main(){ 174 int n,m; 175 while(scanf("%d%d",&n,&m) != EOF){ 176 cout << ans[(n - 1) * 12 + m] << endl; 177 } 178 return 0; 179 }
B题:按顺序不断地确定序列里的数,可以发现:每轮取数都是取入度<=k的最大的数。那么我们只要维护一个优先队列,把当前入度<=k的点全部加进来,然后取数,
注意取完数后k要被更新,表示剩下还能删多少条边,同时要根据取的数的出边去更新其他相关数的入度,如果其他数的入度更新完后<=k,那么入队。
这么做难以计算时间复杂度... bc并没有卡掉我的程序... Lucky。
题解给的是线段树+二分的做法... 就测试数据而言,两种做法的效率差不多。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <ctime> 11 #include <string> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 16 #define MEM(a,b) memset(a,b,sizeof(a)) 17 #define REP(i,n) for(int i=0;i<(n);++i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 20 #define MP(a,b) make_pair(a,b) 21 22 typedef long long ll; 23 typedef pair<int,int> pii; 24 const int INF = (1 << 30) - 1; 25 const int MAXN = 200010; 26 27 int n,m,k; 28 int first[MAXN],ecnt; 29 int deg[MAXN]; 30 int vis[MAXN]; 31 int ans[MAXN],sz; 32 33 struct edge{ 34 int v,next; 35 }e[MAXN * 2]; 36 37 void Add_edge(int u,int v){ 38 e[++ecnt].next = first[u]; 39 e[ecnt].v = v; 40 first[u] = ecnt; 41 } 42 43 void Topo(){ 44 sz = 0; 45 priority_queue<int> Q; 46 while(!Q.empty()) Q.pop(); 47 for(int i = 1; i <= n; ++i) if(deg[i] <= k) Q.push(i); 48 while(!Q.empty()){ 49 int cur = Q.top(); Q.pop(); 50 if(!vis[cur] && deg[cur] <= k){ 51 k -= deg[cur]; 52 deg[cur] = 0; 53 vis[cur] = 1; 54 } 55 else continue; 56 ans[sz++] = cur; 57 for(int i = first[cur]; i != -1; i = e[i].next) if(!vis[e[i].v]){ 58 int v = e[i].v; 59 deg[v]--; 60 if(deg[v] <= k) Q.push(v); 61 } 62 } 63 } 64 65 int main(){ 66 int a,b; 67 while(scanf("%d%d%d",&n,&m,&k) != EOF){ 68 //clock_t st,ed; 69 //st = clock(); 70 MEM(first,-1); 71 ecnt = 0; 72 MEM(deg,0); 73 MEM(vis,0); 74 REP(i,m){ 75 scanf("%d%d",&a,&b); 76 Add_edge(a,b); 77 deg[b]++; 78 } 79 Topo(); 80 //ed = clock(); 81 printf("%d",ans[0]); 82 for(int i = 1; i < sz; ++i) printf(" %d",ans[i]); 83 puts(""); 84 //printf("time : %.2f\n",(double)(ed - st) / CLOCKS_PER_SEC); 85 } 86 return 0; 87 }