Wannafly挑战赛26

25 篇文章 0 订阅
22 篇文章 0 订阅

链接:https://www.nowcoder.com/acm/contest/212/A
作为「Misaka Network」的中心司令塔的 LastOrder出事了,为了维持 「Misaka Network」的正常工作,需要临时选出一个Sister作为中心司令塔。
为了弥补能力上的不足,对于选出的Sister有一些要求。
具体来说,平面上有 n 个 Sister,问能否找到一个Sister作为中心司令塔,使得其他 Sister 都在以她为圆心的一个圆上,如果找不到这样的Sister,则输出 “-1”(不含引号)。
输入描述:
第一行一个数 n
接下来 n 行,第 i 行两个整数 xi, yi ,表示第 i 个Sister在平面上的坐标。
输出描述:
输出共一个数,表示选出的Sister的编号,如果找不到则输出 “-1”。

记录:直接暴力。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1010;
typedef long long LL;
typedef pair<LL, LL> pii;
LL x[MAXN], y[MAXN];
 
int main() {
    int n; scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%lld %lld", &x[i], &y[i]);
    int id = -1;
    for(int i = 1; i <= n; ++i) {
        bool flag = true; LL ans = -1;
        for(int j = 1; j <= n; ++j) {
            if(i == j) continue;
            if(ans < 0) ans = (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
            if(ans != (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])) flag = false;
        }
        if(flag) id = i;
    }
    printf("%d\n", id);
    return 0;
}

链接:https://www.nowcoder.com/acm/contest/212/B
有一天 Misaka 和 Kuroko 在玩一个关于冥土追魂的游戏…
Misaka和Kuroko在一个 n x m 的棋盘上玩游戏,每个格子上都放着一些呱太。游戏共进行 k 回合,每一回合 Kuroko会选有呱太的一行 i,在这之后Misaka会选择一列 j ,并拿走格子 (i, j) 上的所有呱太,Misaka希望自己拿走的呱太尽可能多,而Kuroko不想让Misaka拿走很多呱太,所以她希望拿走的呱太尽可能少。
在一旁围观的恒温死神希望预测结果,请你预测在双方都采取最优策略的情况下,Misaka最终能拿走呱太的数量。
输入描述:
第一行三个数 n, m, k。
接下来 n 行,每行 m 个数,第 i 行第 j 个数表示棋盘第 i 行第 j 列上的呱太数量 ai,j。
输出描述:
输出共一个数,表示在你的预测下,Misaka最终能拿走呱太的数量。

记录:【贪心】
主要要想明白一件事:如果当前行被拿走第一个数字,那么这行一定会被去完或者操作数不够,也就是至多存在一行取了数字但没有被取尽。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1010;
typedef long long LL;
typedef pair<LL, LL> pii;
LL mp[MAXN][MAXN], a[MAXN];
pii dp[MAXN];
 
int main() {
    int n, m, k;
    scanf("%d %d %d", &n, &m, &k);
    int ans = k / m;
    int res = k % m; LL sum = 0;
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            scanf("%lld", &a[j]);
            mp[i][j] = a[j];
            dp[i].first += a[j];
            sum += a[j];
        }
        sort(a + 1, a + m + 1);
        for(int j = m; j >= m - res + 1; --j) {
            dp[i].second += a[j];
        }
    }
    if(ans == n) {
        printf("%lld\n", sum);
        return 0;
    }
    sum = (1ll << 60);
    sort(dp + 1, dp + n + 1);
    LL cnt = 0, num;
    for(int i = 1; i <= ans; ++i) cnt += dp[i].first;
    for(int i = 1; i <= n; ++i) {
        num = cnt + dp[i].second;
        if(i <= ans) num = num - dp[i].first + dp[ans + 1].first;
        sum = min(sum, num);
    }
    printf("%lld\n", sum);
    return 0;
}

链接:https://www.nowcoder.com/acm/contest/212/C
题目描述
听说彩虹有七种颜色?
一维坐标轴上n条线段,每条线段左端点l,右端点r,颜色为c,从中选m种颜色的互不接触的线段,每种颜色可选多条,所选线段的总长度最长为多少?
输入描述:
第一行2个整数 n, m;
接下来n行,每行3个整数l, r, c。
输出描述:
一个整数,表示所选线段的最长的总长度;若选不了,输出-1;

记录:【状压DP+一般DP】
比赛时我写的时候,颜色那么少,肯定按颜色状压呀。dp[i][j]:表示前i段且颜色状态为j时的最长长度,对于当前第i段,枚举所有状态颜色,然后对于当前每一种颜色状态去寻找长度最长且不相交的前一状态,就是在这没想到怎么O(1)转移。。。
题解里直接用一个一般dp维护我上述说的“寻找”,然后就可以O(1)转移。仔细一想也是,前后两个相邻线段无论情况如何,都可以取一下最大值。除此之外,二分预处理一下前驱,用并查集记录,然后状压+一般dp进行转移。
d p [ i ] [ j ∣ r t ] = m a x ( d p [ p r e [ i ] ] [ j ] + 1 l l ∗ s [ i ] . l e n , d p [ i ] [ j ∣ r t ] ) ; dp[i][j | rt] = max(dp[pre[i]][j] + 1ll * s[i].len, dp[i][j | rt]); dp[i][jrt]=max(dp[pre[i]][j]+1lls[i].len,dp[i][jrt]);
d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j ] ) ; dp[i][j] = max(dp[i - 1][j], dp[i][j]); dp[i][j]=max(dp[i1][j],dp[i][j]);

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int MAXN = 1e5 + 5;
const LL INF = (1ll << 60);
int pre[MAXN]; LL dp[MAXN][300];
int n, m = 0, k;

struct node {
    int l, r, c;
    int len;
}s[MAXN];
bool cmp(node x, node y) { return x.r < y.r; }

int get(int x) {
    int L = 0, R = n;
    while(R >= L) {
        int mid = (L + R) >> 1;
        if(s[mid].r < s[x].l) L = mid + 1;
        else R = mid - 1;
    }
    return R;
}

int so(int x) {
    int ans = 0;
    while(x) {
        if(x & 1) ans++;
        x >>= 1;
    }
    return ans;
}

int main() {
    scanf("%d %d", &n, &k);
    for(int i = 1; i <= n; ++i) {
        scanf("%d %d %d", &s[i].l, &s[i].r, &s[i].c);
        s[i].len = s[i].r - s[i].l;
        m = max(m, s[i].c);
    }
    m = (1 << m) - 1;
    sort(s + 1, s + n + 1, cmp);
    for(int i = 1; i <= n; ++i) {
        pre[i] = get(i);
        //printf("## %d %d\n", pre[i], i);
    }
    for(int i = 0; i <= n; ++i) {
        for(int j = 0; j <= m; ++j) {
            dp[i][j] = -INF;
            //if(so(j) == 1) dp[0][j] = 0;
        }
    }
    LL ans = -1; dp[0][0] = 0;
    for(int i = 1; i <= n; ++i) {
        int rt = (1 << (s[i].c - 1));
        for(int j = 0; j <= m; ++j) {
            dp[i][j | rt] = max(dp[pre[i]][j] + 1ll * s[i].len, dp[i][j | rt]);
            dp[i][j] = max(dp[i - 1][j], dp[i][j]);
            if(so(j | rt) == k) {
                ans = max(ans, dp[i][j | rt]);
                //printf("# %d %lld %d\n", (j | rt), ans, i);
            }
        }
    }
/*
    for(int i = 0; i <= n; ++i) {
        for(int j = 0; j <= m; ++j) {
            printf("%d %d %lld\n", i, j, dp[i][j]);
        }
    }
*/
    printf("%lld\n", ans);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值