BUPT2017 wintertraining(16) #9
龟速补题。目前基本弃坑。已暂时放弃 D、I 两题。
下面不再写题意了直接说解法注意事项之类,直接放contest链接。
https://vjudge.net/contest/151537
A.The Perfect Stall
很明显的二分图匹配,可以跑最大流
我是直接写的匈牙利算法,hungary,不是hungry
(虽然读音差不多???
事实证明浪了一个寒假我连hungary算法都不会写了
1 #include <cstdio> 2 #include <vector> 3 #include <cstring> 4 5 using namespace std; 6 7 vector <int> e[210]; 8 int n, m, tim, ans, pre[410], vis[410]; 9 10 int hungary(int u) { 11 vis[u] = tim; 12 for(int v, i = 0;i < e[u].size();i ++) { 13 v = e[u][i]; 14 if(vis[v] != tim) { 15 vis[v] = tim; 16 if(!pre[v] || hungary(pre[v])) 17 return pre[v] = u, 1; 18 } 19 } 20 return 0; 21 } 22 23 int main() { 24 while(~scanf("%d %d", &n, &m)) { 25 ans = 0; 26 memset(e, 0, sizeof e); 27 memset(pre, 0, sizeof pre); 28 memset(vis, 0, sizeof vis); 29 for(int u, v, i = 1;i <= n;i ++) { 30 scanf("%d", &u); 31 for(int j = 1;j <= u;j ++) { 32 scanf("%d", &v); 33 e[i].push_back(v + n); 34 } 35 } 36 for(tim = 1;tim <= n;tim ++) 37 ans += hungary(tim); 38 printf("%d\n", ans); 39 } 40 return 0; 41 }
B.Nim
Nim问题的拓展:
给定一种局面,询问当前局面下
你有多少种不同的保证必胜的操作方法
(又举例把自己难住所以去复习了一下)
显然只要使操作后石子堆异或和为0即可
题外话,之前没怎么注意过运算优先级
然而昨天才认识到AND优先级比OR高
还有位运算清楚不清楚优先级最好加括号
因为今天才知道XOR优先级比 <= 低
1 #include <cstdio> 2 3 int n, k[1010]; 4 5 int main() { 6 while(scanf("%d", &n), n != 0) { 7 int ans = 0, num = 0; 8 for(int i = 1;i <= n;i ++) 9 scanf("%d", &k[i]), num ^= k[i]; 10 for(int i = 1;i <= n;i ++) 11 ans += ((num ^ k[i]) < k[i]); 12 printf("%d\n", ans); 13 } 14 return 0; 15 }
C.sightseeing
一个最短路和次短路计数问题
// unidirectional单向!不要看见un就以为是什么否定前缀
// 就以为是无向边了好吗!naive,多学点英语不好吗
计数比较简单啦,开数组num[2][maxn]
dis[i]表示起点到 i 的最短距离
num[0][i]到 i 的距离为dis[i]的路径数
num[1][i]到 i 的距离为dis[i] + 1的路径数
初始化num[0][s] = 1 结果就是num[0][t] + num[1][t]
由于同时记录最短路和次短路所以如果用spfa会增加很多入队次数可能TLE?
不是很清楚但是我是用的spfa过的,别人题解几乎清一色的dijkstra?
在dr帮助下终于解决了自己的一个困惑
在计数用的spfa中需要同时记录节点和距离
距离数组ddis因为是会被更新的所以入队时需要记录下来距离!
当然我的写法偏非主流,参考价值有限
1 #include <queue> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 6 using namespace std; 7 8 struct node{int x, y, z;}; 9 10 const int maxn = 1010, inf = 111111111; 11 12 int Case, n, m; 13 14 int dis[maxn], ddis[maxn], flag[maxn], vis[3][maxn], num[2][maxn]; 15 16 vector <pair<int, int> > e[maxn]; 17 18 queue <int> q; 19 20 queue <node> qq; 21 22 int main() { 23 scanf("%d", &Case); 24 while(Case -- ) { 25 memset(e, 0, sizeof e); 26 int u, v, w, s, t, p, dd, dp; 27 scanf("%d %d", &n ,&m); 28 for(int i = 1;i <= m;i ++) { 29 scanf("%d %d %d", &u, &v, &w); 30 e[u].push_back(make_pair(v, w)); 31 } 32 scanf("%d %d", &s, &t); 33 for(int i = 1;i <= n;i ++) 34 dis[i] = ddis[i]= inf; 35 dis[s] = ddis[s] = 0, q.push(s); 36 while(!q.empty()) { 37 u = q.front(), flag[u] = 0, q.pop(); 38 for(int i = 0;i < e[u].size();i ++) { 39 v = e[u][i].first, w = e[u][i].second; 40 if(dis[u] + w < dis[v]) { 41 dis[v] = dis[u] + w; 42 if(v != t && !flag[v]) q.push(v), flag[v] = 1; 43 } 44 } 45 } 46 num[0][s] = 1; 47 qq.push((node) {s, 0, 0}); 48 while(!qq.empty()) { 49 u = qq.front().x, p = qq.front().y, dp = qq.front().z, vis[p][u] = 0, qq.pop(); 50 for(int i = 0;i < e[u].size();i ++) { 51 v = e[u][i].first, w = e[u][i].second; 52 if(dp + w <= ddis[v]) { 53 ddis[v] = dp + w; 54 if(ddis[v] == dis[v]) { 55 num[0][v] += num[p][u]; 56 if(v != t && !vis[0][v]) vis[0][v] = 1, qq.push((node) {v, 0, ddis[v]}); 57 } 58 else if(ddis[v] == dis[v] + 1) { 59 num[1][v] += num[p][u]; 60 if(v != t && !vis[1][v]) vis[1][v] = 1, qq.push((node) {v, 1, ddis[v]}); 61 } 62 else if(v != t && !vis[2][v]) vis[2][v] = 1, qq.push((node) {v, 2, ddis[v]}); 63 } 64 else if(dp + w == dis[v] + 1) { 65 num[1][v] += num[p][u]; 66 if(v != t && !vis[1][v]) vis[1][v] = 1, qq.push((node) {v, 1, dp + w}); 67 } 68 } 69 if(p < 2) num[p][u] = 0; 70 } 71 printf("%d\n", num[0][t] + num[1][t]); 72 num[0][t] = num[1][t] = 0; 73 } 74 return 0; 75 }
D.Let it bead
这个题完全是抄别人的代码啊
polya原理是什么啊,好吃吗
等我会了再把坑填上
1 #include <cstdio> 2 3 long long f[50]; 4 5 int gcd(int x, int y) { 6 return y ? gcd(y, x % y) : x; 7 } 8 9 int main() { 10 int c, s; 11 while(scanf("%d %d", &c, &s), c != 0) { 12 f[0] = 1; 13 for(int i = 1;i <= s;i ++) 14 f[i] = f[i - 1] * c; 15 int sum = 0, cnt = 0; 16 for(int i = 1;i <= s;i ++) 17 sum += f[gcd(s, i)]; 18 if(s & 1) cnt = s * f[(s + 1) >> 1]; 19 else cnt = (s >> 1) * (f[(s >> 1) + 1] + f[s >> 1]); 20 printf("%d\n", ((sum + cnt) >> 1) / s); 21 } 22 return 0; 23 }
E.going home
一个比较明显的最小费用最大流
s到H连边,流量1,费用0
m到t连边,流量1,费用0
h到m连边,流量1,费用为距离
直接抄的板子
1 #include <deque> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int maxn = 1010, maxm = 30010, inf = 0x3f3f3f3f; 9 10 int dis(int x, int y) { 11 if(x < y) return y - x; 12 return x - y; 13 } 14 15 struct point { 16 int x, y; 17 int operator - (const point & a) const { 18 return dis(x, a.x) + dis(y, a.y); 19 } 20 }a[maxn], b[maxn]; 21 22 char mmp[maxn]; 23 int n, m, s, t, c1, c2, d[maxn], v[maxn], pre[maxn], incf[maxn]; 24 int len, ans, head[maxn], to[maxm], cap[maxm], cost[maxm], next[maxm], path[maxn]; 25 26 void add(int x, int y, int v, int w) { 27 to[++ len] = y, cap[len] = v, next[len] = head[x], head[x] = len, cost[len] = w; 28 to[++ len] = x, cap[len] = 0, next[len] = head[y], head[y] = len, cost[len] = -w; 29 } 30 31 bool spfa() { 32 deque <int> q; 33 q.push_back(s), incf[s] = inf; 34 memset(d, 0x3f, sizeof d), d[s] = 0; 35 while(!q.empty()) { 36 int x = q.front(); 37 q.pop_front(), v[x] = 0; 38 for(int i = head[x];i;i = next[i]) { 39 if(cap[i] && d[to[i]] > d[x] + cost[i]) { 40 d[to[i]] = d[x] + cost[i]; 41 pre[to[i]] = x, path[to[i]] = i; 42 incf[to[i]] = min(incf[x], cap[i]); 43 if(!v[to[i]]) { 44 v[to[i]] = 1; 45 if(q.empty() || d[to[i]] < d[q.front()]) q.push_front(to[i]); 46 else q.push_back(to[i]); 47 } 48 } 49 } 50 } 51 if(d[t] == inf) return 0; 52 for(int i = t;i != s;i = pre[i]) { 53 cap[path[i]] -= incf[t]; 54 cap[path[i] ^ 1] += incf[t]; 55 } 56 return ans += incf[t] * d[t], 1; 57 } 58 59 int main() { 60 s = 0, t = 201; 61 while(scanf("%d %d", &n, &m), n != 0) { 62 len = 1, c1 = c2 = ans = 0; 63 memset(head, 0, sizeof head); 64 for(int i = 1;i <= n;i ++) { 65 scanf("%s", mmp + 1); 66 for(int j = 1;j <= m;j ++) 67 if(mmp[j] == 'H') { 68 a[++ c1] = (point){i, j}; 69 add(s, c1, 1, 0); 70 } 71 else if(mmp[j] == 'm') { 72 b[++ c2] = (point){i, j}; 73 add(100 + c2, t, 1, 0); 74 } 75 } 76 for(int i = 1;i <= c1;i ++) 77 for(int j = 1;j <= c2;j ++) 78 add(i, j + 100, 1, a[i] - b[j]); 79 while(spfa()); 80 printf("%d\n", ans); 81 } 82 return 0; 83 }
F.Road to Cinema
之前做过的codeforces原题
简单地二分出能到达终点的最小容量
然后在所有容量满足条件的车里找最便宜的即可
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int maxn = 200010; 7 8 int n, k, s, t; 9 10 int a[maxn], b[maxn], c[maxn]; 11 12 bool judge(int x) { 13 long long sum = 0; 14 for(int i = 0;i < k;i ++) { 15 if(c[i] > x) return 0; 16 if(c[i] * 2 <= x) sum += c[i]; 17 else sum += c[i] * 3 -x; 18 } 19 return sum <= t; 20 } 21 22 int main() { 23 int l = 1000000000, r = 0, mid, ans = -1; 24 scanf("%d %d %d %d", &n, &k, &s, &t); 25 for(int i = 1;i <= n;i ++) 26 scanf("%d %d", &a[i], &b[i]), l = min(l, b[i]), r = max(r, b[i]); 27 for(int i = 1;i <= k;i ++) 28 scanf("%d", &c[i]); 29 sort(c + 1, c + k + 1); 30 k ++, c[k] = s; 31 for(int i = 0;i < k;i ++) 32 c[i] = c[i + 1] - c[i]; 33 while(l <= r){ 34 mid = (l + r) >> 1; 35 if(judge(mid)) r = mid - 1, ans = mid; 36 else l = mid + 1; 37 } 38 if(ans == -1) printf("-1"); 39 else { 40 mid = 1000000000; 41 for(int i = 1;i <= n;i ++) 42 if(b[i] >= ans) 43 mid = min(mid, a[i]); 44 printf("%d", mid); 45 } 46 return 0; 47 }
G.play with chain
标题应该翻译成捆绑play?
一道很明显的splay
我能不抄板子打出来?不存在的!
我用指针写的双旋的
FLIP操作就像文艺平衡树一样
把操作区间左边相邻的点转到root
右边相邻的点转到root的右儿子
因为splay保持了原来的顺序
所以要操作的区间就是root的右儿子的左儿子那棵子树
打个翻转标记就完事了
CUT操作其实差不多,只是稍麻烦些
把操作区间左边相邻的点转到root
右边相邻的点转到root的右儿子
然后把要操作的区间拿下来
把剩下的树maintain完成后
把拿下来的区间再放到对应位置即可
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int maxn = 300010; 7 8 struct node { 9 bool rev; 10 int v, siz; 11 node *c[2]; 12 void pushdown(); 13 node *init(int x); 14 15 void update() { 16 siz = c[0]->siz + c[1]->siz + 1; 17 } 18 19 int cmp(int k) { 20 if(k <= c[0]->siz) return 0; 21 if(k == c[0]->siz + 1) return -1; 22 return 1; 23 } 24 }Null, spt[maxn]; 25 26 int n, m, tot, cnt, out[maxn]; 27 28 node *node::init(int x) { 29 v = x, rev = 0, siz = 1; 30 c[0] = c[1] = &Null; 31 return this; 32 } 33 34 void node::pushdown() { 35 if(!rev) return; 36 if(c[0] != &Null) c[0]->rev ^= 1; 37 if(c[1] != &Null) c[1]->rev ^= 1; 38 swap(c[0], c[1]), rev = 0; 39 } 40 41 node *build(int l, int r) { 42 if(l == r) return spt[++tot].init(r); 43 int mid = (l + r) >> 1; 44 node *tmp = spt[++tot].init(mid); 45 if(l < mid) tmp->c[0] = build(l, mid - 1); 46 if(r > mid) tmp->c[1] = build(mid + 1,r); 47 tmp->update(); 48 return tmp; 49 } 50 51 void print(node *&o) { 52 o->pushdown(); 53 if(o->c[0] != &Null) print(o->c[0]); 54 out[cnt ++] = o->v; 55 if(o->c[1] != &Null) print(o->c[1]); 56 } 57 58 void rot(node *&o, int k) { 59 o->pushdown(); 60 node *tmp = o->c[k]; 61 tmp->pushdown(); 62 o->c[k] = tmp->c[!k]; 63 tmp->c[!k]->pushdown(); 64 tmp->c[!k] = o, o->update(); 65 tmp->update(), o = tmp; 66 } 67 68 void splay(node *&o, int k) { 69 o->pushdown(); 70 int k1 = o->cmp(k); 71 if(k1 == -1) return; 72 o->c[k1]->pushdown(); 73 if(k1) k -= o->c[0]->siz + 1; 74 int k2 = o->c[k1]->cmp(k); 75 if(~k2) { 76 if(k2) k -= o->c[k1]->c[0]->siz + 1; 77 splay(o->c[k1]->c[k2], k); 78 if(k2 == k1) rot(o, k1); 79 else rot(o->c[k1], k2); 80 } 81 rot(o, k1); 82 } 83 84 int main() { 85 int a, b, c, len; 86 char str[10]; 87 while(scanf("%d %d", &n, &m), n != -1) { 88 tot = 0, cnt = 0; 89 node *root = build(0, n + 1), *tmp; 90 while(m --) { 91 scanf("%s %d %d", str, &a, &b); 92 a ++, b ++, len = b - a + 1; 93 if(str[0] == 'C') { 94 scanf("%d", &c); 95 splay(root, a - 1); 96 splay(root->c[1], len + 1); 97 tmp = root->c[1]->c[0]; 98 root->c[1]->c[0] = &Null; 99 root->c[1]->update(); 100 root->update(); 101 splay(root, c + 1); 102 splay(root->c[1], 1); 103 root->c[1]->c[0] = tmp; 104 root->c[1]->update(); 105 root->update(); 106 } 107 else { 108 splay(root, a - 1); 109 splay(root->c[1], len + 1); 110 root->c[1]->c[0]->rev ^= 1; 111 } 112 } 113 print(root); 114 for(int i = 1;i < n;i ++) 115 printf("%d ", out[i]); 116 printf("%d\n", out[n]); 117 } 118 return 0; 119 }
H.animals and puzzle
一看是cf的d题就来做了,结果是div1...
好的这个题我当然是看别人题解做的
首先我们很容易求dp[i][j]表示以(i,j)为右下角的最大正方形边长
然后就用到一个神奇的二分,二分里再套一个RMQ就解决了
这个二分是这样的
对于一个单独的查询,我们二分这个查询的答案为mid
然后再在以(x1 + mid - 1, y1 + mid - 1)为左上角
以(x2, y2)为右下角的正方形区域内求dp数组最大值k
如果k >= mid ,那么显然ans >= mid,即mid合法,l = mid +1
否则显然ans < mid,即mid不合法,r = mid -1
更正!效率为O((n^2+q)logn^2)
这里的RMQ为方便起见显然推荐倍增
(我一个一维RMQ宁愿线段树,LCA宁愿树剖的人都含泪推荐倍增了
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int maxn = 1010; 7 8 int n, m, t, x1, y1, x2, y2; 9 10 int a[maxn][maxn], f[maxn][maxn][11][11]; 11 12 int getmax() { 13 int p = 0, q = 0, l1 = 1, l2 = 1, tmp1, tmp2; 14 while(l1 <= x2 - x1 + 1) l1 <<= 1, p ++; 15 p --, l1 >>= 1; 16 while(l2 <= y2 - y1 + 1) l2 <<= 1, q ++; 17 q -- ,l2 >>= 1; 18 tmp1 = max(f[x1 + l1 - 1][y1 + l2 - 1][p][q], f[x2][y1 + l2 - 1][p][q]); 19 tmp2 = max(f[x1 + l1 - 1][y2][p][q], f[x2][y2][p][q]); 20 return max(tmp1, tmp2); 21 } 22 23 bool judge(int r) { 24 x1 += r - 1, y1 += r - 1; 25 bool ret = getmax() >= r; 26 x1 -= r - 1, y1 -= r - 1; 27 return ret; 28 } 29 30 int main() { 31 scanf("%d %d", &n, &m); 32 for(int i = 1;i <= n;i ++) { 33 for(int j = 1;j <= m;j ++) { 34 scanf("%d", &a[i][j]); 35 if(a[i][j]) f[i][j][0][0] = min(f[i - 1][j - 1][0][0], min(f[i - 1][j][0][0], f[i][j - 1][0][0])) + 1; 36 else f[i][j][0][0] = 0; 37 } 38 } 39 40 for(int p = 0, l1 = 1;l1 <= n;l1 <<= 1, p ++) 41 for(int q = 0, l2 = 1;l2 <= m;l2 <<= 1, q ++) { 42 if(p + q == 0) continue; 43 for(int i = l1;i <= n;i ++) { 44 for(int j = l2;j <= m;j ++) { 45 if(p != 0) f[i][j][p][q] = max(f[i][j][p - 1][q], f[i - (l1 >> 1)][j][p - 1][q]); 46 else f[i][j][p][q] = max(f[i][j][p][q - 1], f[i][j - (l2 >> 1)][p][q - 1]); 47 } 48 } 49 } 50 51 scanf("%d", &t); 52 for(int l, r, mid;t --;) { 53 scanf("%d %d %d %d", &x1, &y1, &x2, &y2); 54 l = 0, r = min(x2 - x1 + 1, y2 - y1 + 1); 55 while(l <= r) { 56 mid = (l + r) >> 1; 57 if(judge(mid)) l = mid + 1; 58 else r = mid - 1; 59 } 60 printf("%d\n", r); 61 } 62 return 0; 63 }
I.bear and bowling 4
f[i]代表以 i 为结尾的最大收益
有点奇妙的斜率DP
暂时放弃
J.runaway to a shadow
题意清晰,思路简单。
友情提示:这题不卡精度,只要你开的double不是float
不需要什么各种计算几何算法
只需要高中数学知识和cmath函数的计算几何模拟题
因为自己脑残所以写狗了3次
x,y写错。自己分类讨论好的情况忘写一种。pi 初始成3.141415926535。
1 #include <cmath> 2 #include <cstdio> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxn = 200010; 8 9 typedef long long ll; 10 11 int n, m; 12 13 double x0, Y0, v, t, R; 14 15 double x[maxn], y[maxn], r[maxn]; 16 17 double sqr(double x) { 18 return x * x; 19 } 20 21 struct line { 22 double x, y; 23 bool operator < (const line &a) const { 24 if(x != a.x) return x < a.x; 25 return y < a.y; 26 } 27 }a[maxn]; 28 29 int main() { 30 double pos, tmp, L, RR = 1.0, pi = 3.14159265358, ans = 0.0; 31 scanf("%lf %lf %lf %lf %d", &x0, &Y0, &v, &t, &n), R = v * t; 32 for(int i = 1;i <= n;i ++) { 33 scanf("%lf %lf %lf", &x[i], &y[i], &r[i]); 34 if(sqr(x[i] - x0) + sqr(y[i] - Y0) <= sqr(r[i])) { 35 puts("1.00000000000"); 36 return 0; 37 } 38 if(sqrt(sqr(x[i] - x0) + sqr(y[i] - Y0)) >= R + r[i]) continue; 39 pos = atan2((y[i] - Y0), (x[i] - x0)) + pi; 40 if(sqr(R) + sqr(r[i]) >= sqr(x[i] - x0) + sqr(y[i] - Y0)) tmp = asin(r[i] / sqrt(sqr(x[i] - x0) + sqr(y[i] - Y0))); 41 else tmp = acos((sqr(R) - sqr(r[i]) + sqr(x[i] - x0) + sqr(y[i] - Y0)) / (sqrt(sqr(x[i] - x0) + sqr(y[i] - Y0)) * 2.0 * R)); 42 m ++, a[m].y = pos + tmp ,a[m].x = pos - tmp; 43 if(a[m].x < 0.0) a[m + 1].x = a[m].x + pi * 2.0, a[m].x = 0, a[++ m].y = pi * 2.0; 44 else if(a[m].y > pi * 2) a[m + 1].y = a[m].y - pi * 2, a[m].y = pi * 2, a[++ m].x = 0; 45 } 46 sort(a + 1, a + m + 1); 47 L = a[1].x, RR = a[1].y; 48 for(int i = 2;i <= m;i ++) { 49 if(a[i].x >= RR) ans += RR - L, L = a[i].x, RR = a[i].y; 50 else RR = max(RR, a[i].y); 51 } 52 ans += RR - L; 53 printf("%lf", abs(ans / (pi * 2))); 54 return 0; 55 }
K.sightseeing
貌似高中做过的一个01规划问题
所以很显然的想到二分,然后处理边,判负环
好吧认真的说。显然最后结果必然是一个简单的环(自己思考
然后假设最优路径上fun之和为sf,路径长度为sl
则最优解 ans = sf / sl
那么我们二分一个mid,并把所有边的边长都设为 原长 * mid - fun[to]
若能找到负环,则存在sl * mid - sf <= 0
即mid <= sf / sl ,即 ans >= mid
所以二分就解释清楚了
至于判负环,dfs的spfa效率我不清楚
我用的bfs的spfa判负环,进队次数 >= n 即有负环
注意像我那么写的话,每次spfa开始要同时开始清理上次残留的队列以及visit数组!
1 #include <queue> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 6 using namespace std; 7 8 const int maxn = 1010; 9 const double eps = 1e-4; 10 11 int n, m, c[maxn], f[maxn], vis[maxn]; 12 13 double d[maxn]; 14 15 queue <int> q; 16 17 vector <double> E[maxn]; 18 vector <pair<int, double> > e[maxn]; 19 20 bool spfa() { 21 while(!q.empty()) vis[q.front()] = 0, q.pop(); 22 static int u, v; 23 static double w; 24 for(int i = 2;i <= n;i ++) 25 c[i] = 0, d[i] = 111111111; 26 q.push(1), c[1] = 0; 27 while(!q.empty()) { 28 u = q.front(); 29 q.pop(), vis[u] = 0, c[u] ++; 30 if(c[u] == n) return 1; 31 for(int i = 0;i < e[u].size();i ++) { 32 w = e[u][i].second, v = e[u][i].first; 33 if(d[u] + w <= d[v]) { 34 d[v] = d[u] + w; 35 if(!vis[v]) vis[v] = 1, q.push(v); 36 } 37 } 38 } 39 return 0; 40 } 41 42 bool judge(double x) { 43 for(int i = 1;i <= n;i ++) 44 for(int j = 0;j < e[i].size();j ++) 45 e[i][j].second = x * E[i][j] - 1.0 * f[e[i][j].first]; 46 return spfa(); 47 } 48 49 int main() { 50 int u, v, w; 51 scanf("%d %d", &n, &m); 52 for(int i = 1;i <= n;i ++) 53 scanf("%d", &f[i]); 54 for(int i = 1;i <= m;i ++) { 55 scanf("%d %d %d", &u, &v, &w); 56 e[u].push_back(make_pair(v, w)); 57 E[u].push_back(w); 58 } 59 double l = 0.0, r = 1000.0, mid, ans = 0.0; 60 while(l + eps <= r) { 61 mid = (l + r) / 2.0; 62 if(judge(mid)) l = mid + eps, ans = mid; 63 else r = mid - eps; 64 } 65 printf("%.2f", ans); 66 return 0; 67 }
L.ZS and The Birthday Paradox
好吧这个题我也是看题解做出来的
其实最原始的公式很好推
然后我们需要对结果x/y约分后
分子分母再对mod=1e6+3取模
利用乘法逆元可知若有gcd(x,y)=z
我们求得z对mod的逆元
就可以直接x,y对mod取模
再分别乘以z对mod的逆元,再对mod取模即可
根据原始公式有y = 2^(nk)
x = (2^n)(2^n - 1)(2^n - 2)...(2^n - k + 1)
虽然x有k项,但是我们只需要求x % mod
x中的k项又是连续的,所以当 k >= mod时
一定会有x % mod = 0
k < mod时,直接暴力求x % mod 就行
到这里我们只需要考虑怎么求z了
显然z必然是2^i
求i的话,就是求(2^n - 1)(2^n - 2)...(2^n - k + 1)总共含多少个2
其实就是求(k - 1)! 中有多少个2
这里就能求i了
至此基本解决,再不懂看代码
1 #include <cstdio> 2 3 typedef long long ll; 4 5 const ll _mod = 1000003; 6 7 ll qow(ll x, ll k) { 8 static ll y; 9 x %= _mod, y = 1; 10 for(;k > 0;k >>= 1, x = x * x % _mod) 11 if(k & 1) y = x * y % _mod; 12 return y; 13 } 14 15 int main() { 16 ll n, k, fz, fm, tmp1, tmp2, tmp3; 17 scanf("%I64d %I64d", &n, &k); 18 if(n <= 60 && (1ll << n) < k) { 19 puts("1 1"); 20 return 0; 21 } 22 fz = 1, tmp1 = qow(2, n); 23 for(ll i = 0;i < k;i ++) { 24 fz = fz * (tmp1 - i) % _mod; 25 if(!fz) break; 26 } 27 fm = qow(tmp1, k), tmp2 = n, k --; 28 while(k) k >>= 1, tmp2 += k; 29 tmp3 = qow(2, tmp2), tmp3 = qow(tmp3, _mod - 2); 30 fz = fz * tmp3 % _mod; 31 fm = fm * tmp3 % _mod; 32 fz = (fm - fz) % _mod; 33 if(fz < 0) fz += _mod; 34 printf("%I64d %I64d\n", fz, fm); 35 return 0; 36 }
M.Vasiliy's Multiset
codeforces做过的原题
简单的二进制数的trie树
我写的指针+递归的确丑的没话说
注意!set里始终有0这个元素
所以要一开始手动插入0这个元素
尤其用指针不注意的话直接RE
1 #include <cstdio> 2 3 struct node { 4 int num; 5 node *c[2]; 6 node() { 7 num = 0; 8 c[0] = c[1] =NULL; 9 } 10 }; 11 12 void insert(node *&o, int x, int k) { 13 if(o == NULL) o = new node; 14 o->num ++; 15 if(k == -1) return; 16 insert(o->c[(x & (1 << k)) != 0], x, k - 1); 17 } 18 19 void erase(node *&o, int x, int k) { 20 o->num --; 21 if(k == -1) return; 22 erase(o->c[(x & (1 << k)) != 0], x, k - 1); 23 } 24 25 void ask(node *&o, int x, int k, int ans) { 26 if(k == -1) { 27 printf("%d\n", ans); 28 return; 29 } 30 int d = !(x & (1 << k)); 31 if(o->c[d] != NULL && o->c[d]->num != 0) ask(o->c[d], x, k - 1, ans | (1 << k)); 32 else ask(o->c[!d], x, k - 1, ans); 33 } 34 35 int main() { 36 int n, m; 37 char str[3]; 38 node *root = NULL; 39 insert(root, 0, 30); 40 scanf("%d", &n); 41 while(n --) { 42 scanf("%s %d", str, &m); 43 switch(str[0]) { 44 case '+':insert(root, m, 30);break; 45 case '-':erase(root, m, 30);break; 46 case '?':ask(root, m, 30, 0);break; 47 } 48 } 49 return 0; 50 }