激光控制器
小度一直对外太空充满向往,这次他购买了多台激光发射器,希望通过向天空发射信号来与太空取得联系。
每台激光发射器都配备了一个控制器,初始状态下,所有激光发射器都朝向北方。
控制器每拨动一次,激光发射器便会顺时针旋转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
,需要将 a
,d
,c
,e
修改成 *
才能好像相等。
做法
很典的字符串哈希做法,看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;
}