Bestcoder Round #71 HDU 5620 5621 5622 5623 5624

Bestcoder Round #71
通过数:1(一题被叉)
Div2 的A:
斐波那契数列

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1e5 + 5;
#define LL long long
int cnt;
LL fib[MAXN];
void init()
{
    fib[1] = 1, fib[2] = 2;
    cnt = 2;
    while(fib[cnt] <= 1e18){
        fib[cnt + 1] = fib[cnt] + fib[cnt - 1];
        cnt++;
    }
    for(int i = 1 ; i <= cnt ; i++){
        fib[i] += fib[i - 1];
        if(fib[i] > 1e18){
            cnt = i;
            break;
        }
    }
}
int main()
{
    init();
    int T;
    scanf("%d", &T);
    while(T--){
        LL n;
        scanf("%I64d", &n);
        int mark = upper_bound(fib + 1, fib + 1 + cnt, n) - fib;
        printf("%d\n", mark - 1);

    }
    return 0;
}

A:
刚开始不知道怎么做。
然后发现换一个角度看问题。如果是直接算中间交点个数呢?因为任意三条线不会交于一点,所以两条线交点唯一。
然后再加上边界的n个点。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL unsigned long long
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        LL n;
        cin >> n;
//        scanf("%I64d", &n);
        LL ans1 = n;
//        printf("%I64d\n", n * (n - 1) * (n - 2) * (n - 3));
        LL t1 = n * (n - 1) / 2;
        LL t2 = t1 * (n - 2) / 3;
        LL t3 = (t2 * (n - 3)) / 4;
//        printf("t1 = %llu, t2 = %llu, t3 = %llu\n", t1, t2, t3);
//        LL ans2 = (n) * (n - 1) / 2 * (n - 2) / 3 * (n - 3) / 4;
//        printf("%llu\n", ans1 + t3);
        cout << ans1 + t3 << endl;
    }
    return 0;

}

B:
并不知道怎么写的一道题。
/*
把原图建成无向图染色问题
因为原图的特殊性(一个点只有一个出度),所以不会有环套环的存在。
因此,把图分成环和树分别讨论
环上对答案的贡献用dp[tcnt-1][0]表示
dp[i][j]表示环上第i个点,j=0表示颜色与第一个结点不同,j=1表示颜色与第一个结点不同
假设环上tcnt个点,对答案贡献ans * (dp[tcnt - 1][0] * m)
树上对答案贡献:因为子节点只要与父节点不同即可
故当父节点颜色确定,子节点贡献ans * (m-1)
*/

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
#define LL long long
#define mod (1000000007)
const int MAXN = 100 + 5;
LL fac[MAXN], dp[MAXN][3];
int vis[MAXN];
int to[MAXN];
vector<int>lin[MAXN];
int n, m;
void init()
{
    fac[0] = 1;
    for(int i = 1 ; i < MAXN ; i++) fac[i] = (fac[i - 1] * (i)) % mod;

    dp[0][1] = 1;
    dp[0][0] = 0;
    for(int i = 1 ; i < n ; i++){
        dp[i][0] = (dp[i - 1][0] * (m - 2) % mod + dp[i - 1][1] * (m - 1) % mod) % mod;
        dp[i][1] = dp[i - 1][0];
    }

    memset(vis, -1, sizeof(vis));
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        init();
        for(int i = 0 ; i < n ; i++) scanf("%d", &to[i]);
        LL ans = 1;
        int cnt = 0;
        for(int i = 0 ; i < n ; i++){
            if(vis[i] == -1){
                int u = i;
                while(vis[u] == -1){
                    vis[u] = i;
                    u = to[u];
                }
                if(vis[u] == i){
                    int tcnt = 1;
                    int v = u;
                    u = to[u];
                    while(u != v){
                        u = to[u];
                        tcnt++;
                    }
//                    printf("i = %d, tcnt = %d\n", i, tcnt);
                    ans = (ans * ((dp[tcnt - 1][0] * m) % mod)) % mod;
                    cnt += tcnt;
                }
            }
        }
        for(int i = 0 ; i < n - cnt ; i++)
            ans = (ans * (m - 1)) % mod;
        printf("%I64d\n", ans);
    }
    return 0;
}

C:
赛中懒得dp直接上的记忆化搜索。
然后就被叉掉了。
Dp[i]表示取第i个数时,得到最大差值。转移方程dp[i] = max(a[i] - dp[i-1], dp[i-1)
/*
O(n)处理,保留一个前面最大的a[j] - dp[j - 1]值
*/

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <utility>
using namespace std;
const int MAXN = 50000 + 6;
#define LL long long
int a[MAXN];
LL dp[MAXN];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        int n;
        scanf("%d", &n);
        for(int i = 1 ; i <= n ; i++)   scanf("%d", &a[i]);
        sort(a + 1, a + 1 + n);
        dp[0] = 0;
        LL MMAX = 0;
        for(int i = 1 ; i <= n ; i++){
            LL temp = a[i] - dp[i - 1];
            MMAX = max(MMAX, temp);
            dp[i] = MMAX;
        }
//        for(int i = 1 ; i <= n ; i++)
//            printf("dp[%d] = %I64d\n", i, dp[i]);
        printf("%I64d\n", dp[n]);
    }
    return 0;
}

D:
算复杂度这个解法实际上不正确。
然而还没学LCT和次小生成树,所以就水一发好了。
暴力枚举最小边或最大边,然后做一遍kruskal最小生成树。注意枚举处有一个最优性剪枝。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
#define LL long long
const int MAXN = 2000 + 5;
const int MAXM = 15000 + 5;
struct Edge
{
    int u, v;
    int w;
}edge[MAXM];
int fa[MAXN];
int n, m;
int find_fa(int u){return u == fa[u] ? u : fa[u] = find_fa(fa[u]);}
bool cmp(Edge a, Edge b){return a.w > b.w;}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        for(int i = 1 ; i <= m ; i++) scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
        sort(edge + 1, edge + 1 + m, cmp);
//        for(int i = 1 ; i <= m ; i++){
//            printf("u = %d, v = %d, w = %d\n", edge[i].u, edge[i].v, edge[i].w);
//        }
        int ans = 0;
        int cnt = 0;
        for(int i = 1 ; i <= n ; i++) fa[i] = i;
//        memset(visedge, 0, sizeof(visedge));
        int st;
        for(st = 1 ; st <= m ; st++){
            int u = edge[st].u, v = edge[st].v, w = edge[st].w;
            int fau = find_fa(u);
            int fav = find_fa(v);
            if(fau != fav){
                fa[fau] = fav;
                cnt++;
            }
            if(cnt == n - 1){
                ans = edge[1].w - edge[st].w;
                break;
            }
        }
        if(st > m){
            puts("-1");
            continue;
        }
        ///此处不能++
//        st++;
        for(; st <= m ; st++){
            for(int i = 1 ; i <= n ; i++) fa[i] = i;
            cnt = 0;
            for(int j = st  ; j >= 1  && ans > edge[j].w - edge[st].w ; j--){
                int u = edge[j].u, v = edge[j].v, w = edge[j].w;
                int fau = find_fa(u);
                int fav = find_fa(v);
                if(fau != fav){
                    fa[fau] = fav;
                    cnt++;
                }
                if(cnt == n - 1){
                    ans = min(ans, edge[j].w - edge[st].w);
//            printf("st = %d, ans = %d\n", st, edge[j].w - edge[st].w);
                    break;
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值