现在的位置: 首页 > 综合 > 正文

HDU 多校联合第三场

2013年03月19日 ⁄ 综合 ⁄ 共 8948字 ⁄ 字号 评论关闭

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

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;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

抱歉!评论已关闭.