2024百度之星第三场

激光控制器

小度一直对外太空充满向往,这次他购买了多台激光发射器,希望通过向天空发射信号来与太空取得联系。
每台激光发射器都配备了一个控制器,初始状态下,所有激光发射器都朝向北方。
控制器每拨动一次,激光发射器便会顺时针旋转90度。
因此,随着控制器的多次拨动,激光的朝向将按照“北-东-南-西-北”的顺序循环变化。
这些控制器整齐地排列在一条直线上,可以被视为一条坐标轴,每个整数单位上对应一个控制器。

小度从原点出发,计划进行N次连续的操作。每次操作从当前坐标上的控制器开始,连续拨动一个区间内的所有控制器,并停留在最后一个控制器的位置,拨动包含当前控制器以及最后停留位置对应的控制器。
每次操作用一个整数和一个字符 𝑥 𝑐x c 表示,其中 𝑥x 代表从当前控制器开始连续拨动多少个控制器,𝑐c 表示拨动方向。
𝑐c 为字符 𝑅R 时,表示沿坐标向右操作;𝑐c 为字符 𝐿L 时,表示沿坐标向左操作。
例如, 3 𝐿3 L 表示从当前控制器起向左拨动3个控制器。1 𝑅1 R 表示从当前控制器起向右拨动1个控制器,即停留在当前位置。
通过这种方式,小度可以控制激光发射器的朝向,并向太空发射出特定的信号。

现在给你小度的操作序列,希望你能告诉他最终朝向东方的激光器有多少台。

格式

输入格式:

第 1 行读入 1 个整数 𝑁N,代表操作次数。 (1≤𝑁≤1∗105)(1≤N≤1∗105);
第 22 到 𝑁+1N+1 行,每行一个整数一个字符 𝑥 𝑐x c,表示每次拨动的数量和方向。数据保障小度不会偏离原点 1∗1091∗109 个单位。

输出格式:

一个整数,表示最终朝向东方的激光器有多少台。

样例 1

输入:

4
5 R
5 R
1 L
5 R

复制

输出:

11

复制

样例 2

输入:

5
5 R
10 L
6 R
3 L
4 R

复制

输出:

1

复制

备注

样例1解释:
5 R 拨动【0,1,2,3,4】,当前位置为4;
5 R 拨动【4,5,6,7,8】,当前位置为8;
1 L 拨动【8】,当前位置为8;
5 R 拨动【8,9,10,11,12】当前位置为12;
朝向东方的有拨动一次的【0,1,2,3,5,6,7,9,10,11,12】所以答案为11。

做法

就是看每个点拨动开关几次,次数%4为1就是东边。但是吧,2e9数组开不下,我考时就卡在这,完全忘了还有差分这种东西,明明之前有学这类型的题。。。这题是区间同时加1,我们正常的想法就是开一个2e9的差分数组,但是吧,这个数组里有大量是0的值,就是每次只有区间的两端才被赋值了,有大量的点是0,我们不关心,因此可以利用map作差分数组来实现离散化。我们求的是原数组中值%4为1的个数,每次找到原数组值%4为1的点就可以加上它到下一个点的距离,就是这段区间中符合答案的值的个数了。

#include<bits/stdc++.h> 
using namespace std;
int n;
map<long long,long long> mp;
long long b;
int tot;
long long a[200010][2];//开2e5,每个区间两个端点
char c;
long long pos;
int main( )
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){//构造差分数组
        scanf("%lld",&b);
        cin>>c;
        if(c=='R') {
            mp[pos]++;
            mp[pos+b]--;
            pos+=b-1;
        }
        else {
            mp[pos-b+1]++;
            mp[pos+1]--;
            pos-=b-1;
        }
    }

    for(map<long long,long long>::iterator it=mp.begin();it!=mp.end();it++){//差分数组求前缀和变为原数组
        if(it==mp.begin()){
            a[++tot][0]=it->first;
            a[tot][1]=it->second;
        }
        else{
            a[++tot][0]=it->first;
            a[tot][1]=it->second+a[tot-1][1];
        }
    }

    long long ans=0;
    for(int i=1;i<tot;i++){
        if(a[i][1]%4==1){//算答案
            ans+=a[i+1][0]-a[i][0];
        }
    }

    cout<<ans;
    return 0;
}

最后

嗐,其实这题应该是要写出来的,当时完全没想到,就硬生生卡在数组开不下上了。也算是明显的了,对区间同时加1的操作,然后数据范围很大。不是很敏感吧,对这些知识点的特征。

好像相等

对于两个字符串,如果他们逐位相等,那么便称这两个字符串相等,但是大多数情况下,字符串是不相等的,所以小度定义如果将几种字符修改成字符 * 之后,两个字符串逐位相等了,那么便称这两个字符串好像相等。

现在给定一个长度为 𝑛n 的仅包含小写字母的字符串 𝑠s,多次询问对于该字符串的 [𝑙1,𝑟1][l1​,r1​] 子串与 [𝑙2,𝑟2][l2​,r2​] 子串,是否相等,如果不相等,那么将他们变成好像相等,至少需要将多少种字符修改成字符 *,并输出字符种类。

格式

输入格式:

第 1 行读入 2 个数字 𝑛,𝑞n,q,分别代表字符串长度,以及询问的次数;
第 2 行读入一个字符串 𝑠s,保证该字符均为小写字母;
随后 𝑞q 行每行读入 4 个正整数 𝑙1,𝑟1,𝑙2,𝑟2l1​,r1​,l2​,r2​;
数据范围保证 1≤𝑛,𝑞≤1051≤n,q≤105, 1≤𝑙1,𝑙2,𝑟1,𝑟2≤𝑛1≤l1​,l2​,r1​,r2​≤n,𝑙1≤𝑟1l1​≤r1​,𝑙2≤𝑟2l2​≤r2​,𝑟1−𝑙1=𝑟2−𝑙2r1​−l1​=r2​−l2​。

输出格式:

对于每次询问,输出两行:
第一行输出至少需要将多少种字符修改成 *,如果两个字符串完全相等,则输出 0
第二行从小到大输出需要修改的字符种类,中间不间隔。

样例 1

输入:

9 3
abccbedbe
5 6 8 9
1 3 4 6
1 3 7 9

复制

输出:

0

3
ace
4
acde

复制

备注

样例解释:
对于字符 be 等于字符 be,所以输出 0
对于字符 abc 好像相等字符 cbe,需要将 a ,c ,e 修改成 * 才能好像相等。
对于字符 abc 等于字符 dbe,需要将 ad ,ce 修改成 * 才能好像相等。

做法

很典的字符串哈希做法,看26个字母两个子串区间的哈希值是否相同

#include<bits/stdc++.h> 
using namespace std;
const int p=131;
int n,q;
string s;
int l1,r1,l2,r2;
unsigned long long hx[100010][30];
unsigned long long pre[100010];
int main( )
{
    scanf("%d%d",&n,&q);
    cin>>s;
    pre[0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<26;j++){
            if(s[i-1]-'a'==j) hx[i][j]=hx[i-1][j]*p+s[i-1];
            else hx[i][j]=hx[i-1][j]*p;
        }
        pre[i]=pre[i-1]*p;
    }
    vector<char> v;
    while(q--){
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        v.clear();
        for(int i=0;i<26;i++){
            if(hx[r1][i]-hx[l1-1][i]*pre[r1-l1+1]!=hx[r2][i]-hx[l2-1][i]*pre[r2-l2+1]) v.push_back('a'+i);
        }
        cout<<v.size()<<endl;
        for(int i=0;i<v.size();i++) cout<<v[i];
        cout<<endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值