zoukankan      html  css  js  c++  java
  • HDU 多校联合第三场

    我发现已经无力吐嘈这几次的比赛了。。。这次蹭数据的少了许多,不过出题报告讲的那叫一个玄而又玄,完全没理解他要表达什么

    http://page.renren.com/601081183/note/863771603?ref=minifeed&sfet=2012&fin=1&ff_id=601081183&feed=page_blog&tagid=863771603&statID=page_601081183_2&level=1

    1001

    数论题,当时根本就没想到,也不知道怎么证明。。。题解说A的所有质因子包含在B里边,原因是每一个某进制数都可以写成x = p1^k1 * p2^k2 * p3^k3.... (pi为素数)。所以当B包含A的所有质因子时,A进制数一定能被B进制表示。

    关于怎么判断A的质因子在B里边。打一个sqrt(A)大小的素数表。A不断除掉小于等于sqrt(A)的质因子,并且判断这个质因子是否能被B整除。最后如果A剩下>sqrt(A)的质因子,同样判断这个数是否被B整除。(不可能出现>sqrt(A)的质因子个数多于1的情况。。。)

    View Code
    typedef long long LL;
    const int eps = 1e-8;
    const int inf = ~0u>>2;
    
    using namespace std;
    
    const int N = 1000000;
    
    int prime[1000000];
    bool vis[1000010];
    int cnt, ans;
    
    void init() {
        int i;
        LL j;
        CL(vis, true);
        for(i = 2; i <= N; ++i) {
            for(j = LL(i)*LL(i); j <= N; j += i)
                vis[j] = false;
        }
        cnt = 0;
        for(i = 2; i <= N; ++i)
            if(vis[i])  prime[cnt++] = i;
    }
    
    bool solve(LL A, LL B) {
    
        for(int i = 0; i < cnt; ++i) {
            if(A%prime[i] == 0) {
                if(B%prime[i] != 0) return false;
                while(A%prime[i] == 0)   A /= prime[i];
            }
            if(prime[i] > A)    break;
        }
        if(A > 1)   return B%A == 0;
        return true;
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int t, cas = 0;
        LL A, B;
        init();
        scanf("%d", &t);
        while(t--) {
            cin >> A >> B;
            printf("Case #%d: ", ++cas);
            if(solve(A, B))   puts("YES");
            else    puts("NO");
        }
        return 0;
    }

    1003

    这是我对题解最想吐嘈的题。。。你妹!c和k分不清楚吗?!到底是bi还是bj不知道吗!!!

    吐嘈完毕-_-!

    确实是个好题,把欢乐值当成费用,糖果个数当成流。

    以下为转载内容:http://blog.csdn.net/cyberzhg/article/details/7815790

    当快乐的程度超过b[i]时,多出来的部分就浪费了,为了使浪费尽可能少,我们用费用流加以控制,当获得最大费用最大流的时候,这是的费用的利用率就是最高的。

     

    在建图时只需考虑特殊的糖就可以了,建图方法:

    原点到每个糖:流为1,费用为0

    如果糖对某个人有特殊效果,连边:流为1,费用为0

    人向汇点连边:

      最终快乐的程度不超过b[i]的情况:流为b[i]/k,限制这样的糖的数量,费用为k,因为特殊效果全部利用上了。

      快乐程度超过b[i]的情况:流为1,限制流量不超过b[i],费用为b[i] % k,因为多出来的快乐无效。当b[i] % k == 0时,这样的边没有必要。当b[i] % k == 1时,这时的糖和普通的糖无异,没必要连边。

    ps:做这道题才发现以前的费用流模板是那么的水。。。Orz cyberzhg大神

    View Code
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <ctime>
    #include <queue>
    #include <map>
    #include <sstream>
    
    #define CL(arr, val)    memset(arr, val, sizeof(arr))
    #define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
    #define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
    #define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   (l + r) >> 1
    #define Min(x, y)   x < y ? x : y
    #define Max(x, y)   x < y ? y : x
    #define E(x)    (1 << (x))
    #define iabs(x)  ((x) > 0 ? (x) : -(x))
    
    typedef long long LL;
    const int eps = 1e-8;
    const int inf = ~0u>>2;
    
    using namespace std;
    
    const int N = 110;
    const int M = N*N*2;
    
    int n, m, k;
    int b[N], sumb;
    int c[N][N];
    int S, T;
    
    struct node {
        int from, to, cost, flow, next;   //
    } g[M];
    
    int head[N], t;
    
    void init() {
        CL(head, -1); t = 0;
    }
    
    void add(int u, int v, int f, int w) {
        g[t].from = u; g[t].to = v;  g[t].cost = w; g[t].flow = f;
        g[t].next = head[u]; head[u] = t++;
    
        g[t].from = v; g[t].to = u; g[t].cost = -w; g[t].flow = 0;
        g[t].next = head[v]; head[v] = t++;
    }
    
    void build() {
        init();
        int i, j;
        S = 0; T = m + n + 1;
    
        for(i = 1; i <= n; ++i) {
            add(S, i, 1, 0);    //flow, cost;
        }
        for(i = 1; i<= m; ++i) {
            for(j = 1; j <= n; ++j) {
                if(c[i][j]) add(j, i + n, 1, 0);
            }
        }
        for(j = 1; j <= m; ++j) {
            add(j+n, T, b[j]/k, k);
            if(b[j]%k > 1) {
                add(j + n, T, 1, b[j]%k);
            }
        }
    }
    
    int dis[N];
    int pre[N];
    bool vis[N];
    queue<int> q;
    
    bool spfa() {
        while(!q.empty())   q.pop();
        CL(vis, 0);
        CL(dis, -1);
        CL(pre, -1);
    
        q.push(S); dis[S] = 0;
        vis[S] = true; pre[S] = -1;
    
        int u, v, w, i;
        while(!q.empty()) {
            u = q.front(); q.pop();
            for(i = head[u]; i != -1; i = g[i].next) {
                v = g[i].to;
                w = g[i].cost;
                if(g[i].flow && dis[v] < dis[u] + w) {
                    dis[v] = dis[u] + w;
                    pre[v] = i;
                    if(!vis[v]) {
                        vis[v] = true; q.push(v);
                    }
                }
            }
            vis[u] = false;
        }
        return dis[T] != -1;
    }
    
    int get_flow() {
        int tmp = T;
        int res = inf;
    
        while(pre[tmp] != -1) {
            res = min(res, g[pre[tmp]].flow);
            tmp = g[pre[tmp]].from;
        }
        tmp = T;
        while(pre[tmp] != -1) {
            g[pre[tmp]].flow -= res;
            g[pre[tmp]^1].flow += res;
            tmp = g[pre[tmp]].from;
        }
        return res;
    }
    
    bool solve() {
        int Cost = 0, Flow = 0;
        while(spfa()) {
            Cost += dis[T];
            Flow += get_flow();
        }
        //printf("%d %d\n", Cost, Flow);
        //return Cost + n - Flow >= sumb;
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int t, i, j, cas = 0;
        scanf("%d", &t);
        while(t--) {
            CL(c, 0);
            CL(b, 0);
            sumb = 0;
            scanf("%d%d%d", &n, &m, &k);
            for(i = 1; i <= m; ++i)     {scanf("%d", b + i); sumb += b[i];}
            for(i = 1; i <= m; ++i) {
                for(j = 1; j <= n; ++j) scanf("%d", &c[i][j]);
            }
            printf("Case #%d: ", ++cas);
            build();
            if(solve()) puts("YES");
            else    puts("NO");
        }
        return 0;
    }

    1004

    对字符串添加,删除,更改。。。很明显的dp。。。数据不强,不用BK-Tree优化就可以过。。。

    暴力+dp

    View Code
    int dif[20][20];
    char dic[1600][20];
    char tmp[20];
    int len[1600];
    int n, m;
    
    int solve(char* str1,char* str2, int x, int y) {
            int len1 = x;
            int len2 = y;
            CL(dif, 0);
            for (int a = 0; a <= len1; a++) {
                dif[a][0] = a;
            }
            for (int a = 0; a <= len2; a++) {
                dif[0][a] = a;
            }
            int temp;
            for (int i = 1; i <= len1; i++) {
                for (int j = 1; j <= len2; j++) {
                    if (str1[i - 1] == str2[j - 1]) {
                        temp = 0;
                    } else {
                        temp = 1;
                    }
                    dif[i][j] = min(dif[i - 1][j - 1] + temp, min(dif[i][j - 1] + 1, dif[i - 1][j] + 1));
                }
            }
            return dif[len1][len2];
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int t, i, y, l, cnt, cas = 0;
        scanf("%d", &t);
        while(t--) {
            scanf("%d%d", &n, &m);
            CL(dic, 0);
            CL(len, 0);
            for(i = 0; i < n; ++i) {
                scanf("%s", dic[i]);
                len[i] = strlen(dic[i]);
            }
    
            printf("Case #%d:\n", ++cas);
            while(m--) {
                scanf("%s%d", tmp, &y);
                cnt = 0;
                for(i = 0; i < n; ++i) {
                    l = strlen(tmp);
                    if(iabs(l - len[i]) > y)    continue;
                    if(solve(dic[i], tmp, len[i], l) <= y)    cnt++;
                }
                printf("%d\n", cnt);
            }
        }
        return 0;
    }

     

    1005

    思路是找节点数为 3的环。用dfs可以解决

    开一个cnt[]记录每个节点的状态

    cnt[i] = 0 表示i还未被访问过

    cnt[i] = -1 表示跟i相连的所有子节点还没有被访问完,如果在访问它的所有字节点过程中又访问到它自己,说明有环。

    cnt[i] = 1 表示跟i相连的所有子节点还被访问完。

    用一个pos[]记录每个节点被访问的次序。如果dfs(u)时出现cnt[v] = -1的情况,则判断pos[u] 和pos[v]的距离是否为2.

    View Code
    const int N = 2048;
    
    struct node {
        int to;
        int next;
    } g[N*N];
    
    char str[N][N];
    int head[N], t;
    int cnt[N];
    int pot[N];
    int np;
    bool flag;
    
    void init() {
        CL(head, -1); t = 0;
    }
    
    void add(int u, int v) {
        g[t].to = v; g[t].next = head[u]; head[u] = t++;
    }
    
    void dfs(int cur) {
        cnt[cur] = -1;
        pot[cur] = np++;
        int i, v;
        for(i = head[cur]; i != -1; i = g[i].next) {
            v = g[i].to;
            if(cnt[v] == -1 && iabs(pot[cur] - pot[v]) == 2) {
                flag = true;
                return ;
            } else if(cnt[v] == 0)  {
                dfs(v);
            }
        }
        cnt[cur] = 1;
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int t, i, j, n, cas = 0;
        scanf("%d", &t);
        while(t--) {
            init();
            scanf("%d", &n);
            for(i = 0; i < n; ++i) {
                scanf("%s", str[i]);
                for(j = 0; j < n; ++j) {
                    if(str[i][j] == '1')    add(i, j);
                }
            }
            CL(cnt, 0);
            CL(pot, 0);
            flag = false;
            np = 0;
            for(i = 0; i < n; ++i) {
                if(cnt[i] == 0)   dfs(i);
                if(flag)    break;
            }
            printf("Case #%d: ", ++cas);
            if(flag)    puts("Yes");
            else    puts("No");
        }
        return 0;
    }

    1006

    很裸的线段树染色问题。。。比赛的时候gbx做的

    View Code
    const int N = 100010;
    
    struct node {
        int l, r;
        int col;
    } tree[N<<2];
    
    int num[N*3], cnt;
    int L[N], R[N], M[N];
    int n, m;
    
    int find(int x) {
        int l = 0, r = cnt, mid;
        while(l <= r) {
            mid = MID(l, r);
            if(num[mid] == x)   return mid;
            else if(num[mid] > x)   r = mid - 1;
            else    l = mid + 1;
        }
        return -1;
    }
    
    void creat(int t, int l, int r) {
        tree[t].l = l;
        tree[t].r = r;
        tree[t].col = 0;
        if(l == r)  return ;
        int mid = MID(l, r);
        creat(L(t), l, mid);
        creat(R(t), mid + 1, r);
    }
    
    void push_down(int t) {
        if(tree[t].col != 0) {
            tree[L(t)].col += tree[t].col;
            tree[R(t)].col += tree[t].col;
            tree[t].col = 0;
        }
    }
    
    void updata(int t, int l, int r) {
        if(tree[t].l >= l && tree[t].r <= r) {
            tree[t].col ++;
            return ;
        }
    
        push_down(t);
    
        int mid = MID(tree[t].l, tree[t].r);
    
        if(l > mid) updata(R(t), l, r);
        else if(r <= mid)   updata(L(t), l, r);
        else {
            updata(L(t), l, mid);
            updata(R(t), mid + 1, r);
        }
    }
    
    int query(int t, int p) {
        if(tree[t].l == tree[t].r) {
            return tree[t].col;
        }
        push_down(t);
        int mid = MID(tree[t].l, tree[t].r);
    
        if(p > mid) return query(R(t), p);
        else    return query(L(t), p);
    }
    
    void read() {
        scanf("%d%d", &n, &m);
        cnt = 0;
        for(int i = 0; i < n; ++i) {
            scanf("%d%d", &L[i], &R[i]);
            num[cnt++] = L[i];
            num[cnt++] = R[i];
        }
    
        for(int i = 0; i < m; ++i) {
            scanf("%d", &M[i]);
            num[cnt++] = M[i];
        }
        sort(num, num + cnt);
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int t, i, x, y, cas = 0;
        scanf("%d", &t);
        while(t--) {
            read();
            creat(1, 0, cnt);
            for(i = 0; i < n; ++i) {
                x = find(L[i]);
                y = find(R[i]);
                updata(1, x, y);
            }
            printf("Case #%d:\n", ++cas);
            for(i = 0; i < m; ++i) {
                x = find(M[i]);
                printf("%d\n", query(1, x));
            }
        }
        return 0;
    }

    1009

    对于红蓝相间的块和单色的块分开讨论,单色块是很经典的最大子矩阵问题的变形,记录一下上界,左右边界,找最大面积。

    红蓝相间的块直接dp,f[i][j]表示以i,j为右下角的最大正方形。tmp = min(f[i][j-1] , f[i-1][j]); f[i][j] = max(tmp + mp[i-tmp][j-tmp], 1)

    这个过程画画图就很清楚。因为tmp本身取的求实小的,那么>tmp的那一块肯定是红蓝相间的正方形。

    View Code
    const int N = 1010;
    
    int dp[N][N];
    int mp[N][N];
    int H[N], L[N], R[N];
    int n, m, ans;
    char str[N];
    
    void red_or_blue(int x) {    //单色
        int i, j;
        for(i = 1; i <= m; ++i) {
            H[i] = 0; L[i] = 1; R[i] = m;
        }
    
        int lm, rm;
        for(i = 1; i <= n; ++i) {
            lm = 1, rm = m;
            for(j = 1; j <= m; ++j) {
                if(mp[i][j] == x) {
                    H[j]++;
                    if(L[j] < lm)   L[j] = lm;
                } else {
                    H[j] = 0; lm = j + 1; L[j] = 1; R[j] = m;
                }
            }
            for(j = m; j >= 1; --j) {
                if(H[j]) {
                    if(R[j] > rm)   R[j] = rm;
                    ans = max(ans, (H[j] + R[j] - L[j] + 1)*2);
                } else {
                    rm = j - 1;
                }
            }
        }
    }
    
    void red_and_blue() {     //相间色
        int i, j, x;
        for(i = 1; i <= n; ++i) dp[i][1] = 1;
        for(j = 1; j <= m; ++j) dp[1][j] = 1;
    
        for(i = 2; i <= n; ++i) {
            for(j = 2; j <= m; ++j) {
                dp[i][j] = 1;
                if(mp[i][j] == mp[i][j-1] ||
                   mp[i][j] == mp[i-1][j] ||
                   mp[i][j] != mp[i-1][j-1]) {
                   continue;
                }
    
                x = min(dp[i-1][j], dp[i][j-1]);
    
                if(mp[i][j] == mp[i-x][j-x])  ++x;
                dp[i][j] = max(dp[i][j], x);
                ans = max(ans, dp[i][j]);
            }
        }
        ans <<= 2;
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int t, i, j, cas = 0;
        scanf("%d", &t);
        while(t--) {
            scanf("%d%d", &n, &m);
            CL(mp, 0);
            for(i = 1; i <= n; ++i) {
                scanf("%s", str + 1);
                for(j = 1; j <= m; ++j) {
                    mp[i][j] = (str[j] == 'R');
                }
            }
            ans = 1;
            red_and_blue();
            red_or_blue(0);
            red_or_blue(1);
            printf("Case #%d: %d\n", ++cas, ans);
        }
        return 0;
    }

    1010

    神题意

    题意说明白了相信都会做

    P(r)怎么求,

    比如给出原字典串

    (1)Apple iphone.com ipad.com

    又给出搜索得到的串

    (2)Apple gdfgd.com iphone.com ipad.com

    P(i)表示:(2)串中,前i个串里边有j个串在字典串中包含,那么P(i) = 1.0*j / i;

     AveP = sum(P[i])/num  num表示(2)中有多少个串。

    ans = sum(AveP)/n;

    View Code
    const int N = 10010;
    
    char dic[110][N];
    char res[110][N];
    string s;
    
    double getAveP(char* a, char* b) {
        map<string, int> mp;
        istringstream dic(a);
        istringstream res(b);
    
        int num = 0, cnt = 0, l = 0;
        double ret = .0;
    
        dic >> s;
        while(dic >> s)     mp[s] = 1, num++;
    
        res >> s;
        while(res >> s) {
            cnt++;
            if(mp[s] == 1) {
                l++;
                ret += double(l)/cnt;
            }
        }
        return ret/num;
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int t, n, i, cas = 0;
        scanf("%d", &t);
        while(t--) {
            scanf("%d\n", &n);
    
            for(i = 0; i < n; ++i)  cin.getline(dic[i], N);
            for(i = 0; i < n; ++i)  cin.getline(res[i], N);
    
            double ans = .0;
            for(i = 0; i < n; ++i) {
                ans += getAveP(dic[i], res[i]);
            }
            printf("Case #%d: %.6f\n", ++cas, ans/n);
        }
        return 0;
    }
  • 相关阅读:
    .NET Framework类库大概
    CTS、CLS、CIL与CLR
    .NETFramework、CLR、.NET Framework class library、托管代码是什么
    万维网三大核心技术
    Clang、GCC和LLVM是什么
    常见开源许可证、开源协议GPL、BSD、MIT、Mozilla、Apache和LGPL之间区别
    编译原理之变量、名字与标识符
    编译原理之静态策略与动态策略
    Jupyter Notebook打开任意文件
    修改VsCodes的语言为中文
  • 原文地址:https://www.cnblogs.com/vongang/p/2619532.html
Copyright © 2011-2022 走看看