2015 ACM/ICPC Asia Regional Hefei Online

A-Monitor the Alpacas(hdu 5484)

先给n个点,再给m个点,要从m个点中选出最少的点使得这m个点形成的凸包包含这n个点。因为m比较少,所以我们可以先对n个点求凸包,然后再判断m个点形成的线段是否和凸包相交。然后就得到了各个点可以相连的情况。于是再跑个最小环就是答案了。暴力点可以用floyd。


B-The Relationship in Club(hdu5485)

二分图染色计数。g(n)表示n个点任何满足的二分图有多少种可能。f(n)表示n个点形成联通的二分图的种数。然后求f(n)的时候,需要固定1点在X部。然后根据f(n)就可以同样固定1点在X部进行dp求解了。

详见_

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 1111;
const int MOD = 105225319;

int g[maxn], f[maxn];
int dp[maxn];
int c[maxn][maxn], p2[maxn * maxn];

int n, m;

void init()
{
    p2[0] = 1; c[0][0] = 1;
    for(int i = 1; i < maxn; i ++)
    {
        c[i][0] = c[i][i] = 1;
        for(int j = 1; j < i; j ++)
            c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
    }
}

int inv2 = (MOD + 1) / 2;

void solve()
{
    if(n == 1)
    {
        puts("0");
        return ;
    }
    for(int i = 1; i <= n * n; i ++)
        p2[i] = 1ll * p2[i - 1] * (m + 1) % MOD;

    for(int i = 0; i <= n; i ++)
    {
        g[i] = 0;
        for(int j = 0; j <= i; j ++)
            g[i] = (g[i] + 1ll * c[i][j] * p2[j * (i - j)] % MOD) % MOD;
    }
    f[0] = 0; f[1] = 1;
    for(int i = 1; i <= n; i ++)
    {
        f[i] = 1ll * g[i] * inv2 % MOD;
        for(int j = 1; j <= i - 1; j ++)
        {
            f[i] = (f[i] + MOD - 1ll * c[i - 1][j - 1] * f[j] % MOD * g[i - j] % MOD) % MOD;
        }
    }
    CLR(dp, 0); dp[0] = 1;
    LL ans = 0;
    for(int i = 1; i <= n; i ++)
    {
        for(int j = 1; j <= i; j ++)
            dp[i] = (dp[i]+ 1ll * f[j] * c[i - 1][j - 1] % MOD * dp[i - j] % MOD) % MOD;
    }
    printf("%d\n", dp[n]);
}

int main()
{
    init();
    int T, cas = 1;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d%d", &n, &m);
        printf("Case #%d: ", cas ++);
        solve();
    }
    return 0;
}


C- Difference of Clustering(hdu 5486)

这题暴力左右两边枚举就可以了。需要用链表,开n个vector会MLE。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 1000010;
map<int, int> x, y;

int heada[maxn], headb[maxn];
int nexta[maxn], nextb[maxn];
int vala[maxn], valb[maxn];

int top1, top2;
int sza, szb;
int l[maxn];
int r[maxn];
int sizea[maxn], sizeb[maxn];

int vis[maxn];

vector<int> tmp;

int main(){
    int n, t, cas = 1;
    cin >> t;
    while(t --) {
        scanf("%d", &n);
        x.clear();
        y.clear();
        top1 = 0, top2 = 0;
        sza = szb = 0;
        for(int i = 0; i < n; i ++) {
            int u, v;
            scanf("%d%d", &u, &v);
            int tgt1, tgt2;

            if(x.count(u) == 0) {
                x[u] = tgt1 = top1;
                heada[top1] = -1;
                sizea[top1] = 0;
                top1 ++;
            }else{
                tgt1 = x[u];
            }
            nexta[sza] = heada[tgt1];
            vala[sza] = i;
            heada[tgt1] = sza ++;
            sizea[tgt1] ++;

            l[i] = tgt1;

            if(y.count(v) == 0) {
                y[v] = tgt2 = top2;
                headb[top2] = -1;
                sizeb[top2] = 0;
                top2 ++;
            }else{
                tgt2 = y[v];
            }

            nextb[szb] = headb[tgt2];
            valb[szb] = i;
            headb[tgt2] = szb ++;
            sizeb[tgt2] ++;
            r[i] = tgt2;
        }


        int ansSplits = 0, ansMerges = 0, ansOne = 0;
        for(int i = 0; i < top1; i ++) {
            int rad = rand();
            tmp.clear();
            for(int jj = heada[i]; ~jj; jj = nexta[jj]) {
                int id = vala[jj];
                if(vis[r[id]] == rad) continue;
                tmp.push_back(r[id]);
                vis[r[id]] = rad;
            }
            if(tmp.size() > 1) {
                int sum = 0;
                for(int j = 0; j < tmp.size(); j ++) {
                    sum += sizeb[tmp[j]];
                }
                if(sum == sizea[i]) ansSplits ++;
            }else{
                int sum = sizeb[tmp[0]];
                if(sum == sizea[i]) ansOne ++;
            }
        }
        for(int i = 0; i < top2; i ++) {
            int rad = rand();
            tmp.clear();
            for(int jj = headb[i]; ~jj; jj = nextb[jj]) {
                int id = valb[jj];
                if(vis[l[id]] == rad) continue;
                tmp.push_back(l[id]);
                vis[l[id]] = rad;
            }
            if(tmp.size() > 1) {
                int sum = 0;
                for(int j = 0; j < tmp.size(); j ++) {
                    sum += sizea[tmp[j]];
                }
                if(sum == sizeb[i]) ansMerges ++;
            }
        }
        printf("Case #%d: ", cas ++);
        printf("%d %d %d\n", ansSplits, ansMerges, ansOne);
    }
    return 0;
}

D- Difference of Languages(hdu 5487)

这题也是个暴力,因为两个DFA都只有1000个状态,所以从0 0状态开始广搜就可以了。需要注意的是,一个能走,另一个不能走也可能产生最短解。这个稍微处理一下就好了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 1010;

int dp[maxn][maxn];
pair<int, int> last[maxn][maxn];

int mp1[maxn][26], mp2[maxn][26];
bool ed1[maxn], ed2[maxn];

void dfs(int x, int y)
{
    if(x == 0 && y == 0) return ;
    dfs(last[x][y].xx, last[x][y].yy);
    putchar(dp[x][y] + 'a');
}

int n1, n2;

void solve()
{
    queue<pair<int, int> > Q;
    Q.push(MP(0, 0));
    if(ed1[0] != ed2[0])
    {
        puts("");
        return ;
    }
    CLR(dp, -1); dp[0][0] = 27;
    while(!Q.empty())
    {
        pair<int, int> u = Q.front(); Q.pop();
        for(int i = 0; i < 26; i ++)
        {
            int vx = mp1[u.xx][i], vy = mp2[u.yy][i];
            if(vx == -1 && vy == -1) continue;
            if(vx == -1) vx = n1;
            if(vy == -1) vy = n2;
            if(dp[vx][vy] != -1) continue;
            dp[vx][vy] = i;
            last[vx][vy] = u;
            if(ed1[vx] != ed2[vy])
            {
                dfs(vx, vy); putchar('\n');
                return ;
            }
            Q.push(MP(vx, vy));
        }
    }
    puts("0");
}

int main()
{
    int T, cas = 1; scanf("%d", &T);
    while(T --)
    {
        int n, m, k;
        CLR(mp1, -1); CLR(ed1, false);
        scanf("%d%d%d", &n, &m, &k);
        n1 = n;
        for(int i = 0; i < k; i ++)
        {
            int u; scanf("%d", &u);
            ed1[u] = true;
        }
        for(int i = 0; i < m; i ++)
        {
            int u, v; char o[4];
            scanf("%d%d%s", &u, &v, o);
            mp1[u][o[0] - 'a'] = v;
        }
        CLR(mp2, -1); CLR(ed2, false);
        scanf("%d%d%d", &n, &m, &k);
        n2 = n;
        for(int i = 0; i < k; i ++)
        {
            int u; scanf("%d", &u);
            ed2[u] = true;
        }
        for(int i = 0; i < m; i ++)
        {
            int u, v; char o[4];
            scanf("%d%d%s", &u, &v, o);
            mp2[u][o[0] - 'a'] = v;
        }
        printf("Case #%d: ", cas ++);
        solve();
    }
    return 0;
}

E- Shape

这题不会。


F-Removed Interval(hdu 5489)

这题我脑抽了,写了一个可持久化线段树。而且比赛的时候无线脑抽,导致上来就发现可以敲,然后一个多小时才过掉。这题只需要维护每个位置作为LIS开始位置的长度,然后可以用树状数组,线段树,可持久化线段树之类的简单数据结构维护一下每个值作为LIS最后一个位置的最长长度就好了。然后枚举到i的时候,就看看i-L-1之前比当前值小的LIS最大值就好了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
//#define lson l, m, rt << 1
//#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 100100;
const int maxm = 20*maxn;

int n, L, m, tot;
int a[maxn], t[maxn];
int T[maxm], lson[maxm], rson[maxm], c[maxm];

void init_Hash()
{
    for(int i = 1; i <= n; i ++)
        t[i] = a[i];
    sort(t + 1, t + 1 + n);
    m = unique(t + 1, t + n + 1) - t - 1;
}

int build(int l, int r)
{
    int root = tot ++;
    c[root] = 0;
    if(l != r)
    {
        int mid = (l + r) >> 1;
        lson[root] = build(l, mid);
        rson[root] = build(mid + 1, r);
    }
    return root;
}

int Hash(int x)
{
    return lower_bound(t + 1, t + m + 1, x) - t;
}

void up(int rt)
{
    c[rt] = max(c[lson[rt]], c[rson[rt]]);
}

int query(int rt, int L, int R, int l, int r)
{
    if(L <= l && r <= R)
    {
        return c[rt];
    }
    int m = (l + r) >> 1;
    int ret = 0;
    if(L <= m) ret = max(ret, query(lson[rt], L, R, l, m));
    if(R > m) ret = max(ret, query(rson[rt], L, R, m + 1, r));
    return ret;
}

int update(int rt, int pos, int val, int l, int r)
{
    int root = tot ++;
    if(l == r)
    {
        c[root] = val;
        return root;
    }
    int m = (l + r) >> 1;
    lson[root] = lson[rt];
    rson[root] = rson[rt];
    if(pos <= m) lson[root] = update(lson[rt], pos, val, l, m);
    else rson[root] = update(rson[rt], pos, val, m + 1, r);
    up(root);
    return root;
}

int b[maxn], o[maxn];
#define INF 0x3f3f3f3f

void gao()
{
    CLR(o, INF);
    for(int i = n; i > 0; i --)
    {
        int tmp = lower_bound(o + 1, o + n + 1, b[i]) - o;
        o[tmp] = b[i];
        b[i] = tmp;
    }
}

int main()
{
    int cas = 1, Tt;
    scanf("%d", &Tt);
    while(Tt --)
    {
        tot = 0;
        scanf("%d%d", &n, &L);
        for(int i = 1; i <= n; i ++)
        {
            scanf("%d", &a[i]);
        }
        init_Hash();
        T[0] = build(1, m);
        for(int i = 1; i <= n; i ++)
        {
            int pos = Hash(a[i]); a[i] = pos;
            b[i] = m + 1 - pos;
            int val = 0;
            if(pos > 1) val = query(T[i - 1], 1, pos - 1, 1, m);
            T[i] = update(T[i - 1], pos, val + 1, 1, m);
        }
        gao();
        int ans = query(T[n - L], 1, m, 1, m);
        for(int i = L + 1; i <= n; i ++)
        {
            int tmp = 0;
            if(a[i] > 1) tmp = query(T[i - L - 1], 1, a[i] - 1, 1, m);
            ans = max(ans, tmp + b[i]);
        }
        printf("Case #%d: %d\n", cas ++, ans);
    }
    return 0;
}


G- Simple Matrix(hdu 5490)

这题,对于位置i, j上的一个常数v来说,对n, m位置的答案贡献为 v * C(n - i + m - j, n - i),这个很显然。然后对于每一排的等比数列来说,计算到下一排仍然是等比数列+贡献一个常数。然后对于初始的等差数列,也可以根据常数贡献的方法去算。然后答案就很明显了。然后因为常数贡献的位置只有第一列和第二列,所以可以初始计算出一个组合数后,下面用递推式求出需要的组合数就好了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 10100;
const int MOD = 1000000007;

LL Powmod(LL a, int n)
{
    LL ret = 1;
    a = (a + MOD) % MOD;
    while(n)
    {
        if(n & 1) ret = ret * a % MOD;
        a = a * a % MOD;
        n >>= 1;
    }
    return ret;
}

int a, d, b, q, n, m;

LL C(LL n, int m)
{
    LL ret = 1;
    for(int i = 0; i < m; i ++)
    {
        ret = ret * (n - i) % MOD * Powmod(i + 1, MOD - 2) % MOD;
    }
    return ret;
}

void solve()
{
    LL ans = 0;
    if(n == 0)
    {
        if(m == 0)
        {
            puts("0");
            return ;
        }
        ans = 1ll * b * Powmod(q, m - 1) % MOD;
        printf("%I64d\n", ans);
        return ;
    }
    if(m == 0)
    {
        ans = a + 1ll * d * (n - 1) % MOD;
        printf("%I64d\n", ans % MOD);
        return ;
    }
    if(q==0)
    {
        LL x = C(n + m - 2, n - 1);
        ans = x * b % MOD;
        b = 0;
        q = 1;
    }
    LL X = C(n + m - 1, n - 1);
    int bb = b, qq = Powmod(q - 1, MOD - 2);
    for(int i = 1; i <= n; i ++)
    {
        LL tmp = 1ll * b * qq % MOD;
        LL Y = Powmod(n + m - i, MOD - 2);
        tmp = tmp * X % MOD * Y % MOD * m % MOD;
        b = 1ll * b * q % MOD * qq% MOD;
        ans = (ans + a * X % MOD) % MOD;
        ans = (ans + MOD - tmp) % MOD;
        X = X * (n - i) % MOD * Y % MOD;
        a = d;
    }
    if(q == 1)
    {
        X = C(n + m - 1, n);
        ans = (ans + X * bb % MOD) % MOD;
        printf("%I64d\n", ans);
        return ;
    }
    ans = (ans + b * Powmod(q, m - 1) % MOD) % MOD;
    printf("%I64d\n", ans);
}

int main()
{
    int T, cas = 1;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d%d%d%d%d%d", &b, &q, &a, &d, &n, &m);
        printf("Case #%d: ", cas ++);
        solve();
    }
    return 0;
}

H- The Next(hdu 5491)

据说是水题?

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn=111111;

int s[maxn];

int main(){
    int t, cas = 1;
    LL d;
    int s1, s2;
    cin >> t;
    while(t --) {
        scanf("%I64d%d%d", &d, &s1, &s2);
        int now = 0;
        int cnt = 0;
        while(d) {
            if(d&1)s[now] = 1, cnt ++;
            else s[now] = 0;
            now ++;
            d >>= 1;
        }
        s[now] = 0;
        if(cnt != s2) {
            int pos = -1;
            for(int i = 0; i <= now; i ++) {
                if(s[i] == 0) {
                    cnt ++;
                    pos = i;
                    s[i] = 1;
                    break;
                }
            }
            for(int i = pos; i <= now; i ++) {
                if(s[i] == 1) s1 --;
            }
            int tmp = max(0, s1);
            for(int i = 0; i < pos; i ++) {
                if(tmp) s[i] = 1, tmp --;
                else s[i] = 0;
            }
        }else{
            int pos = -1;
            bool ok = false;
            for(int i = 0; i <= now; i ++) {
                if(s[i] == 0 && ok) {
                    cnt ++;
                    pos = i;
                    s[i] = 1;
                    break;
                }
                if(s[i] == 1) {
                    ok = true;
                }
            }
            for(int i = pos; i <= now; i ++) {
                if(s[i] == 1) s1 --;
            }
            int tmp = max(0, s1);
            for(int i = 0; i < pos; i ++) {
                if(tmp) s[i] = 1, tmp --;
                else s[i] = 0;
            }

        }

        LL ans = 0;
        for(int i = now; i >= 0; i --) {
            ans = (ans << 1) | s[i];
        }
        printf("Case #%d: ", cas ++);
        printf("%I64d\n", ans);
    }
    return 0;
}

I- Find a path(hdu 5492)

把方差式子变换一下,然后把和作为状态暴力dp即可。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 35;
const int inf = 0x3f3f3f3f;

int s[maxn][maxn];
int dp[maxn][maxn][60*30*2];

int main(){
    int t, cas = 1, n, m;
    cin >> t;
    while(t --) {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m; j ++) {
                scanf("%d", &s[i][j]);
            }
        }
        memset(dp, inf, sizeof dp);

        dp[1][1][s[1][1]] = s[1][1] * s[1][1];

        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m; j ++) {
                for(int k = 0; k <= 1800; k ++) {
                    if(dp[i][j][k] == inf) continue;
                    dp[i][j + 1][k + s[i][j + 1]] = min(dp[i][j + 1][k + s[i][j + 1]], dp[i][j][k] + s[i][j + 1] * s[i][j + 1]);
                    dp[i + 1][j][k + s[i + 1][j]] = min(dp[i + 1][j][k + s[i + 1][j]], dp[i][j][k] + s[i + 1][j] * s[i + 1][j]);
                }
            }
        }

        LL ans = inf;
        for(int i = 0; i <= 1800; i ++) {
            ans = min(ans, (n + m - 1ll) * dp[n][m][i] - i * i);
        }
        printf("Case #%d: ", cas ++);
        printf("%I64d\n", ans);
    }
    return 0;
}

J- Queue(hdu 5493)

首先贪心,如果顺序放的话,对于每个数都可以确定出对称的两个位置,由于要字典序最小的。显然我们需要把这个数放在前面,然后就用线段树求一下每次要放的位置就好了。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 100100;

int sum[maxn<<2];

int n;

void PushUp(int rt)
{
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void build(int l = 1, int r = n, int rt = 1)
{
    if(l == r)
    {
        sum[rt] = 0;
        return ;
    }
    int m=(l + r) >> 1;
    build(lson);
    build(rson);
    PushUp(rt);
}
void update(int p, int l = 1, int r = n, int rt = 1)
{
    if(l == r)
    {
        sum[rt] = 1;
        return ;
    }
    int m = (l + r) >> 1;
    if (p <= m) update(p, lson);
    else update(p ,rson);
    PushUp(rt);
}

int query(int p, int l = 1, int r = n, int rt = 1)
{
    if(l == r)
    {
        return l;
    }
    int m = (l + r) >> 1;
    int lsz = m - l + 1 - sum[rt << 1];
    if (lsz >= p) return query(p , lson);
    return query(p - lsz, rson);
}

int a[maxn], r[maxn], b[maxn], ans[maxn];

bool cmp(int i, int j)
{
    return a[i] < a[j];
}

void solve()
{
    sort(b + 1, b + n + 1, cmp);
    int tot = n;
    build();
    for(int i = 1; i <= n; i ++)
    {
        int id = b[i];
        int p = min(r[id] + 1, tot - r[id]);
        if(p <= 0)
        {
            puts("impossible");
            return ;
        }
        int pos = query(p);
        ans[pos] = a[id];
        update(pos);
        tot --;
    }
    for(int i = 1; i <= n; i ++)
        printf("%d%c", ans[i], i == n ? '\n' : ' ');
}

int main()
{
    int T, cas = 1;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++)
        {
            scanf("%d%d", &a[i], &r[i]);
            b[i] = i;
        }
        printf("Case #%d: ", cas ++);
        solve();
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值