2017百度之星初赛b

来源:互联网 发布:gcf软件 编辑:程序博客网 时间:2024/05/17 04:19

题目链接


01:http://acm.hdu.edu.cn/showproblem.php?pid=6114
02:http://acm.hdu.edu.cn/showproblem.php?pid=6115
03:http://acm.hdu.edu.cn/showproblem.php?pid=6116
04:http://acm.hdu.edu.cn/showproblem.php?pid=6117
05:http://acm.hdu.edu.cn/showproblem.php?pid=6118
06:http://acm.hdu.edu.cn/showproblem.php?pid=6119

一些题解


01 Chess

 题意说是要找在n*m的棋盘上最多的车让他们互相不攻击,并且下一行的车要在上一行的车的右边,问摆放的方案数。
 那么一共就有min(n, m)个车,一共有max(n, m)个位置则答案就是Cmax(n, m)min(n, m)。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;const LL maxn(1000005), mod(1e9 + 7);LL Jc[maxn];void calJc()    //求maxn以内的数的阶乘{    Jc[0] = Jc[1] = 1;    for(LL i = 2; i < maxn; i++)        Jc[i] = Jc[i - 1] * i % mod;}/*//拓展欧几里得算法求逆元void exgcd(LL a, LL b, LL &x, LL &y)    //拓展欧几里得算法{    if(!b) x = 1, y = 0;    else    {        exgcd(b, a % b, y, x);        y -= x * (a / b);    }}LL niYuan(LL a, LL b)   //求a对b取模的逆元{    LL x, y;    exgcd(a, b, x, y);    return (x + b) % b;}*///费马小定理求逆元LL pow(LL a, LL n, LL p)    //快速幂 a^n % p{    LL ans = 1;    while(n)    {        if(n & 1) ans = ans * a % p;        a = a * a % p;        n >>= 1;    }    return ans;}LL niYuan(LL a, LL b)   //费马小定理求逆元{    return pow(a, b - 2, b);}LL C(LL a, LL b)    //计算C(a, b){    return Jc[a] * niYuan(Jc[b], mod) % mod        * niYuan(Jc[a - b], mod) % mod;}int main(){    int t;    scanf("%d", &t);    int n, m;    calJc();    while(t--)    {        scanf("%d%d", &n, &m);        printf("%d\n", C(max(n, m),min(n, m)));    }    return 0;}

06 小小粉丝度度熊

 题意很简单,给定n个区间,每个区间有L-R已经被覆盖,给定m个填充剂每一个可以覆盖一个数,问最能连续覆盖多少个数。
 直接合并连续或相交的区间再根据区间开始的数由大到小排序。然后跑一遍记录当前消耗和当前连续数,当消耗的填充剂大于m就把当前首部区间去掉。然后每次比较最大值就可以了。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define rep(i, s, t) for(int i = s;i <= t;i++)#define rap(i, s, t) for(int i = s;i >= t;i--)using namespace std;struct Node{    long long st, en;}node[100004];struct Bag{    long long st, en;}beg[100004];long long n, m;int cmp(Node a, Node b){        return a.st < b.st;}int main(){    while(scanf("%I64d%I64d", &n, &m) != EOF)    {        rep(i, 1, n)            scanf("%I64d%I64d", &node[i].st, &node[i].en);        sort(node + 1, node + 1 + n, cmp);        int cnt = 0;        int xen = 0;        rep(i, 1, n){            if(node[i].st <= xen&&i != 1){                if(node[i].en <= xen)                    continue;                else                {                    beg[cnt].en = node[i].en;                    xen = node[i].en;                }            }            else            {                beg[++cnt].en = node[i].en;                xen = node[i].en;                beg[cnt].st = node[i].st;            }        }        long long xh = 0;        long long ans = 0;        int beginn = 1;        for(int i = 1;i <= cnt;i++){            if(i != 1){                int lsxh = beg[i].st - beg[i - 1].en - 1;                xh += lsxh;            }            while(xh > m)            {                xh -= beg[beginn + 1].st - beg[beginn].en - 1;                beginn++;            }            ans = max(ans, beg[i].en - beg[beginn].st + 1 + m - xh);        }        printf("%I64d\n", ans);    }    return 0;}

补题


02 Factory

 暴力加LCA把所有配对全部加入查询,然后标记问题序号,注意这里不能用公共祖先数组作为距离树根变去除,因为有可能这两个点相同且没有后继即ancestor数组不会更新,那么只有在并查集合并的时候把子树的标记用父数代替,不能像以前这样随意了233333.

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <cmath>#define rep(i, s, t) for(int i = s;i <= t;i++)#define rap(i, s, t) for(int i = s;i >= t;i--)#define inf 0x3f3f3f3fusing namespace std;int n, m;const int M = 100004;vector<int>tree[M];vector<int>query[M];vector<int>queid[M];vector<int>worth[M];vector<int>G[M];bool vis[M];int f[M];//int ancestor[M];int dis[M];int ans[M];int Q;int findd(int x){    return x == f[x]?f[x]:f[x] = findd(f[x]);}void uni(int x, int y){    x = findd(x);    y = findd(y);    if(x != y)        f[y] = x;}void init(){    rep(i, 0, n){        G[i].clear();        vis[i] = false;        tree[i].clear();        query[i].clear();        worth[i].clear();        queid[i].clear();        f[i] = i;        dis[i] = 0;        ans[i] = inf;    }}void input_tree(){    rep(i, 1, n - 1){        int a, b, c;        scanf("%d%d%d", &a, &b, &c);        tree[a].push_back(b);        worth[a].push_back(c);        tree[b].push_back(a);        worth[b].push_back(c);    }}void input_query(){    scanf("%d", &Q);    rep(i, 1, Q)    {        int a, b;        scanf("%d%d", &a, &b);        rep(j, 0, (int)G[a].size() - 1)        {            rep(k, 0, (int)G[b].size() - 1)            {                query[G[a][j]].push_back(G[b][k]);                queid[G[a][j]].push_back(i);                query[G[b][k]].push_back(G[a][j]);                queid[G[b][k]].push_back(i);            }        }    }}void tarjan(int x, int value){    dis[x] = value;    vis[x] = true;    rep(i, 0, (int)tree[x].size() - 1){        int v = tree[x][i];        if(vis[v] == true)            continue;        tarjan(v, value + worth[x][i]);        uni(x, v);        //ancestor[findd(x)] = x;    }    rep(i, 0, (int)query[x].size() - 1){        int v = query[x][i];        if(vis[v]&&ans[queid[x][i]] > dis[x] + dis[v] - 2 * dis[findd(v)])            ans[queid[x][i]] = dis[x] + dis[v] - 2 * dis[findd(v)];        //printf("%d %d %d %d %d %d %d %d\n", x, v, findd(v), dis[x], dis[v], dis[findd(v)], queid[x][i], ans[queid[x][i]]);    }}int main(){    int t;    scanf("%d", &t);    while(t--)    {        scanf("%d%d", &n, &m);        init();        input_tree();        rep(i, 1, m){            int a;            scanf("%d", &a);            rep(j, 1, a){                int b;                scanf("%d", &b);                G[i].push_back(b);            }        }        input_query();        tarjan(1, 0);        rep(i, 1, Q)            printf("%d\n", ans[i]);    }    return 0;}
原创粉丝点击