2021天梯赛选拔随缘补题.jpg

和去年比起来稍微强了一点点,但还是很拉胯,还要继续努力呀

P1892 [BOI2003]团伙

https://www.luogu.com.cn/problem/P1892

思路:当时想着并查集加邻接表,但是因为过于紧张瞎写的邻接表(?)
然后理所当然地写残了,骗了一半分;然后查了题解,是并查集 + 反集,出现了知识盲区——什么是反集?
好像也叫种类并查集,就是说,并查集数组开2倍,[1, n]代表朋友,[n + 1, 2 * n]代表敌人
如果a和b是敌,合并a + n和b,b + n和a
如果b和c是敌,合并b + n和c,c + n和b
然后神奇地把a和c合并了!

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1010;

int p[maxn * 2];

int find(int x)
{
    if(p[x] != x) return p[x] = find(p[x]);
    return p[x];
}

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1;i <= n * 2; i++) p[i] = i;
    char op[2];
    while(m--)
    {
        int a, b;
        scanf("%s%d%d", op, &a, &b);
        if(op[0] == 'F') p[find(a)] = find(b);
        else
        {
            p[find(a + n)] = find(b);
            p[find(b + n)] = find(a);
        }
    }
    int ans = 0;
    for(int i = 1;i <= n; i++)
        if(p[i] == i) ans++;
    printf("%d\n", ans);
    return 0;
}

P1325 雷达安装

https://www.luogu.com.cn/problem/P1325
思路:由每个点可以求出它需要的雷达在哪个区间里,然后就变成了熟悉的区间取点问题(简单贪心),排个序判断一下再记录答案就可以了。当时因为之前的一道图论心态有点炸,这题属实不应该做不上= =

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1010;

typedef struct{
    double l, r;
}P;

P p[maxn];
int n;
double d;

bool cmp(P p1, P p2)
{
    return p1.r < p2.r;
}

int main()
{
    scanf("%d%lf", &n, &d);
    for(int i = 1;i <= n; i++)
    {
        double x, y, z;
        scanf("%lf%lf", &x, &y);
        z = sqrt(d * d - y * y);
        p[i].l = x - z;
        p[i].r = x + z;
    }
    sort(p + 1, p + 1 + n, cmp);
    int ans = 1;
    double s = p[1].r;
    for(int i = 2;i <= n; i++)
    {
        if(p[i].l > s)
        {
            ans++;
            s = p[i].r;
        }
    }
    printf("%d\n", ans);
    return 0;
}

P1308 [NOIP2011 普及组] 统计单词数

思路:这题卡住了我是没想到的,到结束了才知道连续空格的事情,属实不应该。学长说了一个在串的首尾各加一个空格就可以直接用KMP做了,就非常之巧妙。但是C++的Sring究极强,有函数可以直接用。
这里参考了这篇博客,string的函数太香了!
C++万岁——
https://blog.csdn.net/qq_33933704/article/details/79188028

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

int ne[23];

string a, b;

int main()
{
    getline(cin, a);
    getline(cin, b);
    a = " " + a + " ";
    b = " " + b + " ";
    for(int i = 0;i < a.size(); i++)
        if(a[i] >= 'A' && a[i] <= 'Z') a[i] += 32;
    for(int i = 0;i < b.size(); i++)
        if(b[i] >= 'A' && b[i] <= 'Z') b[i] += 32;
    if(b.find(a) == string::npos) printf("-1\n");
    else
    {
        int cnt = 0;
        int ans = b.find(a);
        int s = b.find(a);
        while(s != string::npos)
        {
            cnt++;
            s = b.find(a, s + 1);
        }
        printf("%d %d\n", cnt, ans);
    }
    return 0;
}

P2113 看球泡妹子

https://www.luogu.com.cn/problem/P2113

思路:01背包的三维dp,数据范围很小所以不需要压缩成二维。
dp[i][j][k]表示前i场看j场小红精彩度是k的小明的精彩度。
dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - 1][k - b[p] - b[q]] + a[p] * a[q])
需要注意一下初始化,初始化成负无穷,然后dp[i][0][0]要置0(此处是考虑只看1场),k从0开始枚举(题中给的c可能小)。

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

typedef struct{
    int p, q;
}T;

int n, m, k, c, sum;
int a[111], b[111], dp[111][111][2021];
T t[111];

int main()
{
    memset(dp, 128, sizeof(dp));
    scanf("%d%d%d%d", &n, &m, &k, &c);
    for(int i = 1;i <= n; i++) scanf("%d", &a[i]);
    for(int i = 1;i <= n; i++) scanf("%d", &b[i]);
    for(int i = 1;i <= m; i++)
    {
        int p, q;
        scanf("%d%d", &p, &q);
        t[i].p = p;
        t[i].q = q;
        sum += b[p] + b[q];
    }
    for(int i = 0;i <= m; i++) dp[i][0][0] = 0;
    for(int i = 1;i <= m; i++)
    {
        int p = t[i].p;
        int q = t[i].q;
        for(int j = 1;j <= i; j++)
        {
            for(int w = 0;w <= sum; w++)
            {
                dp[i][j][w] = dp[i - 1][j][w];
                if(w >= b[p] + b[q])
                    dp[i][j][w] = max(dp[i - 1][j][w], dp[i - 1][j - 1][w - b[p] - b[q]] + a[p] * a[q]);
            }
        }
    }
    int ans = -1;
    for(int i = c;i <= sum; i++) ans = max(ans, dp[m][k][i]);
    printf("%d\n", ans);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值