CF226 Div2 (E)

本文探讨了三个算法挑战题:寻找包含特定字符串的子串数量、计算质数相关的函数值总和以及利用灯光照亮路径的最大长度。文章提供了详细的解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

B. Bear and Strings

有一串字符串,从中取子串(必须包括bear),问有多少个子串。

input
bearbtear
output
6
有一个字符串:*****bear*******bear

对于第一个bear,前面的字符和后面的字符各取不同的个数可以组合为不同子串,

而对于第二个bear,前面的字符只能到第一个bear的e为止,否者就被第一个bear的子串集所包括。而后面的字符个数还是不限个数。

int main ()
{
    int sum = 0, len, i, j;
    char str[5005];
    cin>>str;
    len = strlen(str);
    i = 0;
    char s[] = "bear";
    i = strstr(str, s) - str;
    if (i < 0) cout<<"0"<<endl;
    else
    {
        sum += (i + 1) * (len - i - 3);
        while(1)
        {
            j = strstr(str + i + 1, s) - str;
            if (j < 0) break;
            sum += (j - i) * (len - j - 3);
            i = j;
        }
        cout<<sum<<endl;
    }
    return 0;
}


C. Bear and Prime Numbers

输入N个数,数字范围为 [2, 10^7], 其中F(x) 为 N个数字中x的倍数的个数。输入M对整数对(L,R)。接下来对于每对(L,R)做如下操作:

从[L,R]当中依次取出质数x,求F(x) 的和

Sample test(s)
input
6
5 5 7 10 14 15
3
2 11
3 12
4 4
output
9
7
0
  1. The first query l = 2r = 11 comes. You need to count f(2) + f(3) + f(5) + f(7) + f(11) = 2 + 1 + 4 + 2 + 0 = 9.
  2. The second query comes l = 3r = 12. You need to count f(3) + f(5) + f(7) + f(11) = 1 + 4 + 2 + 0 = 7.
  3. The third query comes l = 4r = 4. As this interval has no prime numbers, then the sum equals 0.

这道题目我在比赛中把素数筛选出来, 然后将N个数字分别求质因数,算出F(x)。虽然之后求m次为O(1)。但之前的预处理复杂度高,TLE了。

有一个很巧妙的方法,就是一边筛选素数,一边处理F(x)的值。

using namespace std;
int p[maxn+10], a[maxn+10], s[maxn+10];
int main ()
{
    int n;
    scanf("%d", &n);
    for (int i = 0, x; i < n; i++)
    {
        scanf("%d", &x);
        a[x]++;
    }
    for (int i = 2; i <= maxn; i++)
    {
        if (!p[i]) for (int j = i; j <= maxn; j += i)
        {
            p[j] = 1;
            s[i] += a[j];
        }
        s[i] += s[i - 1];
    }
    int m, l ,r;
    scanf("%d", &m);
    while(m--)
    {
        scanf("%d%d", &l, &r);
        l = min(l, maxn);
        r = min(r, maxn);
        printf("%d\n", s[r] - s[l - 1]);
    }
    return 0;
}

D. Bear and Floodlight

一只想从小熊从X轴的L点走到R点,但所走的路必须被灯照亮。有N盏灯(最大为20),每盏灯在(X,Y)处,灯的张角为α。问小熊从L点出发最多能走多远(如果能到R,便停下,所以最大为R-L)

Sample test(s)
input
2 3 5
3 1 45
5 1 45
output
2.000000000

假设此时已经点亮了[L,D], 接下来任意选一盏还未点亮的灯,可以照亮多少路程? 在计算几何中有通过旋转向量变为另一个向量,有:

灯(x,y),从灯指向(D,0)的向量 (dx,dy)= (d - x, -y)

旋转之后(dx, dy) = (dx·cos(angle) - dy·sin(angle), dx·sin(angle) + dy·cos(angle))

需要注意,旋转之后可能向量指向第一象限,此时可以照亮到无穷远处。


接下来就是如何确定最远距离了,采用DP。

将20盏灯用二进制的不同位来表示,0代表没开,1代表开了。比如dp[6] = 110, 即第二和第三盏灯打开了,而其他灯没有开。接下来采用如下的状态转移方程:

dp[ i or 2j ] = max(dp[ i or 2j], dp[ i ] + cal() ) 

其中j为没有打开的灯,而cal()就是上述的计算方法。

从0开始遍历到2^n - 1,不断更新最值,最后得到的dp[2^n - 1]就是最大值。(注意一开始要将所有的dp[]初始化为L)

#include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 1000
#define INF 1<<25
#define N 21
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
using namespace std;
double dp[1 << N], sinn[N], coss[N], x[N], y[N], l, r, a;
double cal(double d, int i)
{
    double dx = d - x[i], dy = -y[i];
    double ddx, ddy;
    ddx = dx * coss[i] - dy * sinn[i];
    ddy = dx * sinn[i] + dy * coss[i];
    if (ddy >= 0) return r;
    return x[i] + dy / ddy * ddx;
}
int main ()
{
    int n;
    cin>>n>>l>>r;
    for (int i = 0; i < n; i++)
    {
        scanf("%lf%lf%lf", x + i, y + i, &a);
        a = a / 180 * M_PI;
        sinn[i] = sin(a), coss[i] = cos(a);
    }
    for (int i = 0; i < 1 << n; i++) dp[i] = l;
    for (int i = 0; i < 1 << n; i++)
    {
        for (int j = 0; j < n; j++) if (!(i & 1 << j))
            dp[i | 1 << j] = max(dp[i | 1 << j], cal(dp[i], j));
    }
    printf("%.9lf\n", min(dp[(1 << n) - 1], r) - l);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值