题意:
给出一个只由 0和1 构成的子串 t ,要你求出一个原串,并且原串长度不大于两倍子串长度,同时原串的循环节最短。
思路:
仔细想想不难发现,当字串都是0或都是1的时候,原串只需要和字串一样即可;当字串既包含0又包含1的时候,原串只有两种可能,101010…或者是010101…。
为什么这么说呢?因为原串的长度可以是字串的二倍,那我只需要在字串的每一位旁边补上和它不同的数字即可。比如说1110,我在第一位数字后面补0,第二位数字后面补0,第三位后面补0,第四位前面补1,这样就是10101010,保证了是字串的同时也保证了循环节最短。
代码:
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
long long int s[N];
vector<long long int> pre;
int main()
{
int t;
cin >> t;
while(t--)
{
int a , b, q;
cin >> a >> b >> q;
for(int i = 0 ; i < q ; i++)
{
long long int l , r;
long long int res = 0;
cin >> l >> r;
long long int z1;
long long int sd = a*b;
z1 = l/sd*sd;
if(z1 < l)
{
z1 = z1+sd;
}
long long int z2;
z2 = z1+sd;
for(long long int j = z1 ; j < z2 ; j++)
{
if((j%a)%b!=(j%b)%a)
res++;
}
//cout << res << endl;
z2 = r/sd*sd;
long long int k = (z2/sd-z1/sd)*res;
if(k<0)
k = 0;
//cout << k << endl;
for(long long int j = l ; j < z1 ; j++)
{
if((j%a)%b!=(j%b)%a)
k++;
}
for(long long int j = z2 ; j <= r ; j++)
{
if((j%a)%b!=(j%b)%a)
k++;
}
s[i] = k;
}
for(int i = 0 ; i < q-1 ; i++)
{
cout << s[i] << ' ';
}
cout << s[q-1] << endl;
}
return 0;
}