神奇字符串的定义为: 只含有1和2, 且将其按照连续的1和2拆开后,对应的每部分数字数量恰好和原字符串相同
例如: 1 22 11 2 1 22 1 22 11 2 11 22 ...... 每部分对应的1和2个数为
1 2 2 1 1 2 1 2 2 1 2 2 ...... 恰好等于原串
现给定N,求神奇串的前N位中有多少个1 .
输入格式:
第一行输入一个T,代表数据组数
接下来的T行,输入N
1 <= N <= 100000
输出格式:
对每一组输入,在一行中输出前N位中1的个数。
输入样例:
1
6
输出样例:
3
解题思路:
此题其实只要把原数组推出来就很简单了,那么我们如何推呢?
一个数在数组中代表着两个意义,一个是对应的数值,一个是从前往后每个块(连续相同的数)中的数量,所以我们就可以使用双指针来写。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N],c[N];
//a为原数组,c为原数组对应位置的值,但是代表块中的数的数量
void intt(){
memset(a,0,sizeof a);
memset(c,0,sizeof c);
int now=1,idx=1;//now为现在的填充值,idx为慢指针(跑块的数组)
for(int i=1;i<=N-5;i++){
a[i]=c[i]=now;//同步更新
c[idx]--;//因为新加了一个值,所以慢指针对应的块所需的数量减少 1
if(c[idx]==0){//当 c[idx]==0 时,说明这个块已经完成了,那么我们就需要转换填充值了
//假设我们 now现在为 1,因为这个块我们都是用 1填充,所以如果后面还是 1,这个块中的数的数量就超额了
//所以我们要把 1变成 2
if(now==1)now=2;
else now=1;
idx++;//寻找下一个块
}
}
}
int main(){
intt();//模拟原数组
int t;cin >> t;
while(t--){
int ans=0,n;
cin >> n;
for(int i=1;i<=n;i++){
if(a[i]==1)ans++;
}
cout << ans << endl;
}
return 0;
}