C
题意
现有一个字符串 ,执行若干 copy 操作:将 copy到 的字符添加到末尾。
进行 q次询问,每次询问需要回答最终结果串 s的某个位置的字符。
找下标,然后再通过下标输出
从最后一段一直往前模拟递推字符在启示串中的位置即可
递归
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2*1e5+10;
ll sum[N],l[N],r[N];
char s[N];
int main()
{
int t;
cin>>t;
while(t--)
{
int n,c,q;
cin>>n>>c>>q;
cin>>s+1;
sum[0]=n;
for(int i=1;i<=c;i++)
{
cin>>l[i]>>r[i];
sum[i]=sum[i-1]+r[i]-l[i]+1;
}
for(int i=0;i<q;i++)
{
ll x;
cin>>x;
for(int j=c;j>=1;j--)//有递归那感觉
{
if(x>sum[j-1]&&x<=sum[j])//一直向前搜索,直到找到最初始的l,r
x=l[j]+x-sum[j-1]-1;//x-sum[j-1]是x在第j次复制的串中的第几个位置
//如abcdcd中的第二个d下标是6,x=6,而sum[j-1]=4,6-4=2,
//所以这个d是第j次复制的串的第二个元素
//然后还有l[j]是第j次复制时的最左边的下标,这里的l[j]就为3,
//(从abcdcd中第一个c开始,然后长度为2,因为是包括c本身得所以要-1)
//最终这个式子得到6-4+3-1=4,4是小于等于sum[1]的,所以再执行一次,
//x=1+4-0-1=4,for循环执行完了,直接cout<<s[4]<<endl;
//再举一个例
//abcdcdcdc 找最后一个c
//123456789
// 1 1 1
}
cout<<s[x]<<endl;
}
}
return 0;
}
D
题意
给出两个01串s和t,每次操作可以把s中两个不同字符中间的字符翻转,问能否通过这种操作使得变为t,如果可以,至少需要多少步?
分析
这个操作的本质其实就是,把连续的一段1,变长或者变短,还可以移动位置,但是不可以与其他1的全段相连,所以这种操作不会改变序列中全段的数量.
比如01001可以变成00101,01101等等.首先我们需要特判一下字符串起始和最后的位置字符是否相同,因为这两个位置字符是永远无法修改的.
然后我们只需要check两个串中的1全串是否数量相等即可.
那最小步数怎么算呢?比如把01100变成00110,我们发现最少操作步数其实就是全段左右端点变化的距离之和,累加起来就是答案.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10,INF=0x3f3f3f3f;
char s1[N],s2[N];
int main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
{
int n;
cin>>n>>s1+1>>s2+1;
if(s1[1]!=s2[1]||s1[n]!=s2[n]){
cout<<-1<<endl;
continue;
}
vector<pair<int,int> >v1,v2;
for(int i=1;i<=n;i++){
if(s1[i]=='0')continue;
int j=i;
while(j+1<=n&&s1[j+1]=='1')j++;
v1.push_back({i,j});
i=j;
}
for(int i=1;i<=n;i++)
{
if(s2[i]=='0')continue;
int j=i;
while(j+1<=n&&s2[j+1]=='1')j++;
v2.push_back({i,j});
i=j;
}
if(v1.size()!=v2.size()){
cout<<-1<<endl;
continue;
}
ll res=0;
for(int i=0;i<v1.size();i++){
auto[l1,r1]=v1[i];
auto[l2,r2]=v2[i];
res+=abs(l2-l1)+abs(r2-r1);
}
cout<<res<<endl;
}
return 0;
}