CF226 Div2 (E)

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

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;
}


CF1583E 是 Codeforces 平台上的一道编程竞赛题目,题目标题为 "Cesium",属于 Codeforces Round #760 (Div. 3) 的一部分。这道题目的核心是构造一个满足特定条件的排列(permutation),并且要求选手能够处理不同情况下的构造逻辑。 题目大意是给定一个长度为 $ n $ 的排列 $ p $,要求构造一个排列,使得对于每个位置 $ i $,其值 $ p_i $ 满足以下条件之一: - $ p_i = i $ - $ p_i = i + 1 $ - $ p_i = i - 1 $ 换句话说,每个元素必须与其索引值相邻(包括等于自身索引的情况)。如果无法构造这样的排列,则输出 `-1`。 解题的关键在于理解哪些 $ n $ 值可以构造出满足条件的排列,并找出构造策略。通过分析,可以发现: - 当 $ n \equiv 2 \mod 3 $ 时,无法构造出满足条件的排列。 - 构造方法通常采用分块策略,例如将排列按照 2、1、3 的模式循环构造,例如 $ [2, 1, 3] $,$ [2, 1, 3, 4] $,等等,以确保每个元素都满足条件[^1]。 以下是一个 Python 实现的示例代码,用于判断是否可以构造满足条件的排列,并输出结果: ```python def solve(n): if n % 3 == 2: print(-1) return res = [] for i in range(1, n + 1, 3): if i + 1 <= n: res.append(i + 1) res.append(i) else: res.append(i) if i + 2 <= n: res.append(i + 2) print(' '.join(map(str, res))) # 示例输入 solve(5) # 输出示例:2 1 3 5 4 ``` 在上述代码中,构造逻辑基于每三个连续的数字,将中间的两个数字交换位置,同时保留第三个数字。这样可以确保所有元素都满足题目要求。 ### 相关问题 1. 如何判断一个排列是否满足 CF1583E 的构造条件? 2. 为什么当 $ n \equiv 2 \mod 3 $ 时无法构造满足条件的排列? 3. CF1583E 的构造策略是否唯一?是否存在其他构造方法? 4. 如何调整 CF1583E 的构造逻辑以适应不同的排列长度? 5. 在编程竞赛中,如何快速识别类似 CF1583E 的构造问题并设计解决方案?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值