• 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
    ", 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
    ", 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
    ", 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
    ", ((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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
  • 相关阅读:
    cocos2d-x Tests讲解 Particle System(粒子系统)
    c++ 知识点
    详解C/C++函数指针声明
    VS中的路径宏 vc++中OutDir、ProjectDir、SolutionDir各种路径
    cocos2d-x学习知识点记录
    Ogre实现简单地形
    Ogre内部渲染流程分析系列
    gcc/g++编译
    gcc和g++的区别
    Hack with rewrite
  • 原文地址:https://www.cnblogs.com/ytytzzz/p/6479054.html
Copyright © 2020-2023  润新知