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 }
View Code

 

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 }
View Code

 

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 } 
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code
posted @ 2017-02-28 15:22  ztztyyy  阅读(212)  评论(0编辑  收藏  举报