【多校10】HDU 5407 5410 5411 5414 5416

  • 最後一場多校,記錄一下。。。
  • 最近一個月聽周的《晴天》聽瘋了。。單曲循環一千萬次- -!

  • 這場是朝鮮金策工業大學出的題,感受到了完全不同的畫風。。有兩點印象深刻

    • 第一,題目描述不拖泥帶水,非常清晰,可讀性好,題目表述非常簡潔。感覺就應該這樣啊,,見過太多題目強行加入一個奇怪的故事背景,搞啥?自認爲增加了趣味性,其實適得其反。。這一點真是值得學習。
    • 第二,標程寫得很棒,想說,這種風格調教出來的代碼纔是給別人看的好麼–

HDU5407 CRB and Candies

  • LCM((n0),(n1)(nn))
  • F(n)=LCM((n0),(n1)(nn))
    以及
    G(n)=LCM(1,2,n)
    則有
    F(n)=G(n+1)n+1
    爲啥捏?不造哇( ⊙o⊙ )。。。
  • 顯然G(1)=1 ,考慮G(n) 的質因數分解形式,知道

    G(n)=G(n1),G(n1)p,if n=pkif n!=pk
    其中p 表示一個質數,即判斷n 是否能表達成某個質數的整數k 次方.
  • 最後的除以n+1 部分需要用逆元處理一下

/* **********************************************

  File Name: 5407.cpp

  Auther: [email protected]

  Created Time: 2015年08月21日 星期五 09時06分16秒

*********************************************** */
#include <bits/stdc++.h>
using namespace std;

/*
 * let f(n)=lcm(C(n,0),...,C(n,n)),
 * g(n)=lcm(1,2,...,n).
 * Then f(n)=g(n+1)/(n+1)..
 * g(1)=1,
 * g(n)=g(n-1) if n != p^k, as p is a prime
 *     =g(n-1)*p if n == p^k.
 */

typedef long long ll;
const int MOD = 1000000007;
const int MAX = 1000002;

int g[MAX] = {0};
bool is_prime[MAX];

//return: gcd(a, b).
ll extgcd(ll a, ll b, ll& x, ll& y) {
    ll d = a;
    if (b) {
        d = extgcd(b, a % b, y, x);
        y -= (a / b) * x;
    } else {
        x = 1, y = 0;
    }
    return d;
}

ll mod_inverse(ll a, ll mod) {
    ll x, y;
    extgcd(a, mod, x, y);
    return (x % mod + mod) % mod;
}

int main() {
    memset(is_prime, true, sizeof(is_prime));
    for (int i = 2; i <= MAX / i; ++i) {
        for (int j = i * i; j < MAX; j += i) {
            is_prime[j] = false;
        }
    }
    for (int i = 2; i < MAX; ++i) {
        if (is_prime[i]) {
            for (ll j = i; j < MAX; j *= i) {
                g[j] = i;
            }
        }
    }
    g[1] = 1;
    for (int i = 2; i < MAX; ++i) {
        if (g[i]) {
            g[i] = (ll)g[i] * g[i - 1] % MOD;
        } else {
            g[i] = g[i - 1];
        }
    }
    /*
    for (int i = 1; i < 10; ++i) {
        printf("g[%d] = %d\n", i, g[i]);
    }
    */

    int T;
    scanf(" %d", &T);
    while (T--) {
        int x;
        scanf(" %d", &x);
        printf("%d\n", (int)(((ll)g[x + 1] * mod_inverse(x + 1, MOD)) % MOD));
    }
    return 0;
}

HDU5410

  • 買東西,拿糖
  • 奇怪的揹包,題解做了一些分析,然後搞啊搞,先排序什麼的。。。
  • 然而窩搞啊搞了好久,搞了一個更奇怪的多重揹包dp
  • 將每種商品拆成1,2,4,,2k 組合,這是典型的多重揹包做法,但是這個問題的特殊性是,比如在買了2 件該物品後,再買4 件該物品,得到的糖不再是2Ai+Bi 而是2Ai 。於是對拆完後的所有商品做dp 。考慮dp[i][j][0] 表示前i 件商品,花費j ,且不拿第i 件物品最多得到的糖;dp[i][j][1] 表示…拿了至少1 件第i 種物品最多能得到的糖。那麼:
    dp[i][j][0]=maxdp[i1][j][0 or 1],dp[i1][j][0], i i

    dp[i][j][1]=max ofdp[i1][jw[i]][0 or 1]+Ai+Bi,dp[i1][jw[i]][0]+Ai+Bi,dp[i1][jw[i]][1]+Ai,i  i
  • 簡單分析一下,原來每件商品至多被拆成log Wi 件,總共至多爲nlog Wmax 件,總狀態則爲mnlogWmax 每次轉移爲O(1) 的,第一維空間可以優化掉,於是時間複雜度O(mnlogWmax) ,空間複雜度O(m) ,足夠通過本題數據。
/* **********************************************

  File Name: 5.cpp

  Auther: [email protected]

  Created Time: 2015年08月20日 星期四 12時32分36秒

*********************************************** */
#include <bits/stdc++.h>
using namespace std;

const int MAX = 1024;
struct Node {
    int w;
    int a;
    int b;
};
vector<Node> V;
vector<int> pre;
int W[MAX], A[MAX], B[MAX];
int dp[MAX << 1][2];
int n, m;

int main() {
    int T;
    scanf(" %d", &T);
    while (T--) {
        scanf(" %d %d", &m, &n);
        V.clear();
        pre.clear();
        V.push_back((struct Node){0, 0});
        pre.push_back(0);

        for (int i = 0; i < n; ++i) {
            scanf(" %d %d %d", W + i, A + i, B + i);
            /* gao */
            Node tp;
            int k = 1;
            int idx = (int)V.size();
            while (k * W[i] <= m) {
                tp.w = k * W[i];
                tp.a = A[i] * k;
                tp.b = B[i];
                //tp.c = A[i] * k + B[i];
                V.push_back(tp);
                pre.push_back(idx);
                k <<= 1;
            }
        }

        memset(dp, 0, sizeof(dp));
        for (int i = 1; i < (int)V.size(); ++i) {
            for (int j = m; j >= 0; --j) {
                //dp[j] = max(dp[j], dp[j - V[i].w] + V[i].c);
                //dp[i][j][0] = ..
                if (i == pre[i]) {
                    dp[j][0] = max(dp[j][0], dp[j][1]);
                    if (j >= V[i].w) {
                        dp[j][1] = max(dp[j][1], max(dp[j - V[i].w][0], dp[j - V[i].w][1]) + V[i].a + V[i].b);
                    }
                } else {
                    if (j >= V[i].w) {
                        dp[j][1] = max(dp[j][1], dp[j - V[i].w][0] + V[i].a + V[i].b);
                        dp[j][1] = max(dp[j][1], dp[j - V[i].w][1] + V[i].a);
                    }
                }
            }
        }
        int ans = max(dp[m][0], dp[m][1]);
        printf("%d\n", ans);
    }
    return 0;
}

HDU5411

  • 關係矩陣搞出來求和即可,構造出分塊矩陣即可。題解構造出的矩陣爲(n+1)×(n+1) 我的是2n×2n ,簡單優化一下才能通過。。
/* **********************************************

  File Name: 5411.cpp

  Auther: [email protected]

  Created Time: 2015年08月20日 星期四 18時11分09秒

*********************************************** */
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MOD = 2015;
const int MAX = 101;
struct Mat {
    int n;
    int a[MAX][MAX];
    Mat(int _n = 0, bool flag = false) {
        n = _n;
        memset(a, 0, sizeof(a));
        if (flag) {
            for (int i = 0; i < n; ++i) {
                a[i][i] = 1;
            }
        }
    }
    Mat operator*(const Mat& b)const {
        Mat res(n);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (a[i][j] == 0) continue;
                for (int k = 0; k < n; ++k) {
                    res.a[i][k] += a[i][j] * b.a[j][k];
                    if (res.a[i][k] >= MOD) {
                        res.a[i][k] %= MOD;
                    }
                }
            }
        }
        return res;
    }
};

Mat fast_pow(Mat a, int m) {
    Mat res(a.n, true);
    while (m) {
        if (m & 1) {
            res = res * a;
        }
        a = a * a;
        m >>= 1;
    }
    return res;
}

int main() {
    int T;
    scanf(" %d", &T);
    while (T--) {
        int n, m;
        scanf(" %d %d", &n, &m);
        Mat res(n << 1);
        for (int i = 1; i <= n; ++i) {
            int k, x;
            scanf(" %d", &k);
            while (k--) {
                scanf(" %d", &x);
                res.a[i - 1][x - 1] = 1;
            }
        }
        for (int i = n; i < (n << 1); ++i) {
            res.a[i - n][i] = 1;
            res.a[i][i] = 1;
        }
        res = fast_pow(res, m);
        /*
        for (int i = 0; i < res.n; ++i) {
            for (int j = 0; j < res.n; ++j) {
                printf("%d ", res.a[i][j]);
            }
            puts("");
        }
        */
        int sum = 1;
        for (int i = 0; i < n; ++i) {
            for (int j = n; j < (n << 1); ++j) {
                sum += res.a[i][j];
            }
        }
        sum %= MOD;
        printf("%d\n", sum);
    }
    return 0;
}

HDU5414

  • 仔細分析後,只要滿足

    • |s||t|
    • s 能匹配成t 的子序列
    • tk 個字母連續相同,則sk 個也必須對應相同

    就可以滿足。唯一比較難想的是諸如ale如果添加到apple,似乎需要往a 後面加2p 才能得到,但其實可以通過先加一個p ,然後再向a 後加1p ,就可以成功避開題目c!=d 的限制

 /* **********************************************

  File Name: 5414.cpp

  Auther: [email protected]

  Created Time: 2015年08月21日 星期五 10時33分17秒

*********************************************** */
#include <bits/stdc++.h>
using namespace std;

const int MAX = 100007;
char s[MAX], t[MAX];

int main() {
    int T;
    scanf(" %d", &T);
    while (T--) {
        scanf(" %s %s", s, t);
        int len1 = strlen(s), len2 = strlen(t);
        if (len1 > len2 || s[0] != t[0]) {
            puts("No");
            continue;
        }
        char c = t[0];
        int k = 0;
        for (int i = 0; i < len2; ++i) {
            if (t[i] == c) ++k;
            else break;
        }
        for (int i = 0; i < len1; ++i) {
            if (s[i] == c) --k;
            else break;
        }
        if (k > 0) {
            puts("No");
            continue;
        }
        int i = 0, j = 0;
        while (i < len1 && j < len2) {
            s[i] == t[j] ? (++i, ++j) : ++j;
        }
        puts(i == len1 ? "Yes" : "No");
    }
    return 0;
}

HDU5416

  • 考慮到異或運算的特殊性質,設1 爲根,對子樹中不經過根的路徑,不妨假設路徑上最高(設若每條邊長爲1,則此處高度即爲到根距離)的一個點爲u ,且路徑由xuuy 兩段組成,那麼
    val(xy)=val(xu)val(uy)=0val(ux)val(uy)=(val(1u)val(1u))val(ux)val(uy)=val(1x)val(1y)
    於是只需要預處理出1 到各個點的路徑異或值即可。統計的時候組合一下即可,另外f(u,v)u 可以等於v ,因此當Query 0 時要多注意一下。
/* **********************************************

  File Name: 5416.cpp

  Auther: [email protected]

  Created Time: 2015年08月21日 星期五 09時53分14秒

*********************************************** */
#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> P;
typedef long long ll;
const int MAX = 100007;
const int MAX_VAL = MAX << 1;

vector<P> G[MAX];
bool vis[MAX];
int cnt[MAX_VAL];

void dfs(int u, int val) {
    vis[u] = true;
    if (u ^ 1) {
        ++cnt[val];
    }

    for (auto it = G[u].begin(); it != G[u].end(); ++it) {
        if (vis[it->first]) continue;
        dfs(it->first, (it->second) ^ val);
    }
}

int main() {
    int T;
    scanf(" %d", &T);
    while (T--) {
        int n, q;
        scanf(" %d", &n);
        for (int i = 1; i <= n; ++i) {
            G[i].clear();
        }
        int u, v, c;
        for (int i = 1; i < n; ++i) {
            scanf(" %d %d %d", &u, &v, &c);
            G[u].push_back(P(v, c));
            G[v].push_back(P(u, c));
        }
        memset(vis, false, sizeof(vis));
        memset(cnt, 0, sizeof(cnt));
        dfs(1, 0);

        scanf(" %d", &q);
        while (q--) {
            scanf(" %d", &c);
            ll ans = 0LL;
            if (c == 0) {
                ans += n + cnt[0];
                for (int i = 0; i < MAX_VAL; ++i) {
                    ans += (ll)cnt[i] * (cnt[i] - 1) / 2;
                }
            } else {
                for (int i = 0; i < MAX_VAL; ++i) {
                    ans += (ll)cnt[i] * (cnt[i ^ c]);
                }
                ans >>= 1;
                ans += cnt[c];
            }
#ifdef ONLINE_JUDGE
#define lld I64d
#endif
            printf("%lld\n", ans);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章