RCC 2014 Warmup (Div. 2)

题目链接:http://codeforces.com/contest/417 

这可能是算很简单的一场CF了。

A题:大意是要让一些人进决赛, 有两种方式一种是C道题,晋级n个人, 还有一种是d道题, 晋级1个人, 现在给出要晋级的人数, 求最少需要多少道题目。 计算几种可能的情况, 比较一下即可。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int c, d, m, n, k;

int main(){
    scanf("%d%d%d%d%d", &c, &d, &n, &m, &k);
    int x, y;
    int res = (m*n) - k;
    if(res < 0) res = 0;
    x = res*d;
    y = res/n * c;
    if(res % n != 0){
        int n1 = y + c;
        int n2 = y + (res%n) * d;
        y = n1 < n2 ? n1 : n2;
    }
    printf("%d\n", x < y? x : y);
    return 0;
}


B题:大意是描述了某个系统后台处理数据的模式, 对于每个用户K有相同ID来标记相同的code. 我们要确定的是, 对于某个用户K在出现标记为X的代码时, X-1标号的代码必须要出现过。 模拟即可

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N];

int main(){
    int n;
    scanf("%d", &n);
    bool suc = 1;
    memset(a, -1, sizeof(a));
    while(n--){
        int x, k;
        scanf("%d%d", &x, &k);
        if(suc == 0) continue;
        if(x == 0 && a[k] == -1) a[k] = 0;
        else{
            if(x <= a[k]) continue;
            else if(x == a[k] + 1) a[k] = x;
            else suc = 0;
        }
    }
    if(suc) printf("YES\n");
    else printf("NO\n");
    return 0;
}


C题:一个简单的构造题。 题意是:有n个球队互相踢比赛, 每两个球队之间最多踢一场比赛, 现在已知每支球队都踢了K场比赛, 构造一种可能的情况。 首先N支球队最多踢n*(n-1)/2场比赛, 先预判断一下n*k是否超过这个数字。

如果没超过我们可以这样构造: 球队1与2,3...踢, 球队2与3,4...踢,...... 球队n与1,2..踢,依此构造。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

int main(){
    int n, k;
    scanf("%d%d", &n, &k);
    int t = n*(n-1)/2;
    if(n*k > t) printf("-1\n");
    else{
        printf("%d\n", n*k);
        for(int i = 1; i <= n; ++i){
            for(int j = i + 1; j <= i + k; ++j){
                printf("%d %d\n", i, (j-1)%n + 1);
            }
        }
    }
    return 0;
}


D题:稍微困难, 状态压缩DP。 题意是某人有n个朋友, 要请他们完成m道题目(m < 20), 每个朋友帮忙都有要求, 一是要求有n个显示屏, 二是要给x卢布(RUS)的报酬, 每个显示屏b元, 给出每个朋友能做出的题目具体编号, 求要做出所有题目要花多少钱。 考虑到m较小, 我们可以用状态压缩DP来解决。 由于显示器可以分时复用,所以我们可以先将所有朋友按显示器个数从小到大排序,这样到后面选择的时候可以保证前面所选的人可以肯定有足够的显示器支持。 状态压缩DP显然向后DP比较方便。同时要注意数据的范围。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = (1<<20) | 0x10;
const LL INF = ((LL)1 << 60);
LL f[N];
int n, m;
LL b;
struct node{
    int x, n;
    int slo;
}a[110];

bool cmp(node a, node b){
    return a.n < b.n;
}

int main(){
    scanf("%d%d%I64d", &n, &m, &b);
    for(int i = 0; i < n; ++i){
        int x, k, t;
        scanf("%d%d%d", &a[i].x, &a[i].n, &t);
        for(int j = 0; j < t; ++j){
            int num;
            scanf("%d", &num);
            a[i].slo |= 1 << (num - 1);
        }
    }

    sort(a, a + n, cmp);
   // memset(f, INF, sizeof(INF));
    for(int i = 1; i < (1<<m); ++i){
        f[i] = INF;
    }
    LL ans = INF;
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < (1<<m); ++j){
            LL tmp = (LL)a[i].x + f[j];
            if(tmp < f[j|a[i].slo])
                f[j|a[i].slo] = tmp;
        }
        if(ans > f[(1 << m) - 1] + a[i].n * b)
            ans = f[(1 << m) - 1] + a[i].n * b;
    }
    if(ans == INF) ans = -1;
    printf("%lld\n", ans);
    return 0;
}



E题:看了别人的思路。 同样是一道构造题。用到了矩阵的知识。 给出m, n 要求构造出一个矩阵满足, 每一行每一列的数平方和都是一个完全平方数。 思路很巧。 考虑到m*1和1*n的两个矩阵, 假如这两个矩阵都满足平方和为完全平方数的话, 那么这两个矩阵的乘积就是一个满足条件的矩阵(自己试试看)。问题转化为给出一个n,如何构造n个数使他们的平方和为完全平方数。 考虑这个等式:(n-1)+ (n/2 - 1)^2 = (n/2)^2; 由此可知, 在n等于偶数的情况下,n-1个1 和 一个 (n/2-1)可以构造成功。 如果n是奇数如何解决?可以将其中的一个1变成2,那么通过调整之后可以知道(n+1)/2 , 2, n-2满足条件。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N = 110;
int a[N], b[N];

void gao(int n, int *a){
    if(n == 1) a[0] = 1;
    else if(n == 2){
        a[0] = 3;
        a[1] = 4;
    }
    else{
        if(n & 1){
            for(int i = 0; i < n - 2; ++i) a[i] = 1;
            a[n-2] = 2;
            a[n-1] = (n >> 1) + 1;
        }
        else{
            for(int i = 0; i < n - 1; ++i) a[i] = 1;
            a[n-1] = (n >> 1) - 1;
        }
    }
}

int main(){
    int n, m;
    scanf("%d%d", &m, &n);
    gao(m, a);
    gao(n, b);
    for(int i = 0; i < m; ++i){
        for(int j = 0; j < n; ++j)
            printf("%d ", a[i]*b[j]);
        printf("\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值