2018"百度之星"程序设计大赛 - 资格赛

BB

好了我活了
这么长时间不写题就是会变菜啊
这种题写这么长时间QAQ

T1

这个题刚看到的时候一脸mb
然后看到数据范围就放心了
就写了个子集枚举就交上去了
但是要注意的是最后统计答案的时候,是每个数字出现的次数两两相乘再求和

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 10000 + 5;
int n,m,k;
int all[MAXN];
bool solve(int jh) {
    //TODO: init
    int tmp[MAXN] = {0};
    for(int i = 0;i < n;i ++) {
        tmp[i] = all[i];
    }
    //TODO: make tmp by jh
    for(int t = 0;t < m;t ++) {
        if((jh >> t) & 1)
            continue;
        for(int i = 0;i < n;i ++)
            tmp[i] |= (1 << t);
    }
    //TODO: unique
    sort(tmp, tmp + n);
    int l = 0,r = 0;
    int tot = 0;
    while(true) {
        while(tmp[l] == tmp[r])
            r ++;
        if(r > n)
            break;
        tmp[tot ++] = r - l;
        l = r;
    }
    //TODO: get ans
    int ans = 0;
    for(int i = 0;i < tot;i ++)
        for(int j = i + 1;j < tot;j ++)
            ans += tmp[i] * tmp[j];
    return ans >= k;
}

int solve() {
    int ans = 0;
    for(int i = 0;i < (1 << m);i ++) {
        ans += solve(i);
    }
    return ans;
}

int T;
int main() {
    scanf("%d", &T);
    for(int t = 1;t <= T;t ++) {
        memset(all, 0, sizeof(all));
        scanf("%d %d %d",&n, &m, &k);
        for(int i = 0;i < n;i ++) {
            for(int j = 0;j < m;j ++) {
                char t = getchar();
                while(!isalpha(t))
                    t = getchar();
                if(t == 'A')
                    all[i] |= (1 << j);
            }
        }
        printf("Case #%d: %d\n", t,solve());
    }
}

T2

emmmm T2还是有点坑的吧,要注意到字典序最小的当然就是一个字母啦!
然后就是26个前缀和,还挺好写的

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 100000 + 5;
int T;
int sum[26][MAXN];
int n,q;
char c[MAXN];
int main()
{
    scanf("%d",&T);
    for(int t = 1;t <= T; t ++)
    {
        printf("Case #%d:\n",t);
        scanf("%d %d",&n,&q);
        memset(sum,0,sizeof(sum));
        for(int i = 1;i <= n;i ++)
        {
            c[i] = getchar();
            while(!isalpha(c[i]))
                c[i] = getchar();
        }
        for(int i = 1;i <= n;i ++)
            sum[c[i] - 'A'][i] ++;
        for(int j = 0;j < 26;j ++)
            for(int i = 1;i <= n;i ++)
                sum[j][i] += sum[j][i - 1];
        int a,b;
        while(q --)
        {
            scanf("%d %d",&a,&b);
            for(int i = 0;i < 26;i ++)
                if(sum[i][b] - sum[i][a - 1])
                {
                    printf("%d\n", sum[i][b] - sum[i][a - 1]);
                    break;
                }
        }
    }
    return 0;
}

T3

这是个二分图匹配?或者说网络流?
不知道,不会做
等题解吧……
【我一定好好学网络流

T4

弃疗
破题能做?

T5

T6

签到题吧……
我是跑了两遍克鲁斯卡尔
然后傻傻的吧红色和蓝色给交换掉
【这套题是告诉我们题目难度与顺序无关吗233333

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 100000 + 5;
int n,m;
struct edge
{
    int f,t,v;
    char c;
    bool operator < (const edge &b)const
    {
        return v < b.v;
    }
}e[MAXN];
struct bcj
{
    int fa[MAXN];
    void init()
    {
        for(int i = 1;i <= n;i ++)
            fa[i] = i;
        return;
    }
    int find(int x)
    {
        return fa[x] == x ? x : fa[x] = find(fa[x]);
    }
    bool same(int x,int y)
    {
        return find(x) == find(y);
    }
    void merge(int x,int y)
    {
        x = find(x);
        y = find(y);
        fa[x] = y;
        return;
    }
}b;
int ans[MAXN],tmp[MAXN];
queue <int> q;
int kru()
{
    int tot = 0,count = 0;
    sort(e + 1, e + m + 1);
    b.init();
    while(!q.empty())
        q.pop();
    for(int i = 1;i <= m;i ++)
    {
        if(e[i].c != 'B' && !b.same(e[i].f, e[i].t))
        {
            tot += e[i].v;
            count ++;
            b.merge(e[i].f, e[i].t);
        }
        else
            q.push(e[i].v);
    }
    return count == n - 1 ? tot : -1;
}
void tj()
{
    int t = kru();
    if(t == -1)
    {
        for(int i = 1;i <= m;i ++)
            ans[i] = -1;
        return;
    }
    for(int i = 1;i < n - 1;i ++)
        ans[i] = -1;
    ans[n - 1] = t;
    for(int i = n;i <= m;i ++)
    {
        ans[i] = ans[i - 1] + q.front();
        q.pop();
    }
    return;
}
void change(int x)
{
    switch (e[x].c)
    {
        case 'B':e[x].c = 'R';break;
        case 'R':e[x].c = 'B';break;
        default:break;
    }
    return;
}
int really(int i)
{
    if(ans[i] == -1)
        return tmp[i];
    if(tmp[i] == -1)
        return ans[i];
    return min(ans[i],tmp[i]);
}
int T;
int main()
{
    scanf("%d",&T);
    for(int t = 1;t <= T;t ++)
    {
        printf("Case #%d:\n",t);
        scanf("%d %d",&n,&m);
        memset(tmp,0,sizeof(tmp));
        memset(ans,0,sizeof(ans));
        for(int i = 1;i <= m;i ++)
            scanf("%d %d %d %c",&e[i].f, &e[i].t, &e[i].v, &e[i].c);
        tj();

        for(int i = 1;i <= m;i ++)
            change(i);
        for(int i = 1;i <= m;i ++)
            tmp[i] = ans[i];
        tj();

        for(int i = 1;i <= m;i ++)
            ans[i] = really(i);
        for(int i = 1;i <= m;i ++)
            printf("%d\n",ans[i]);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值