当 、
或
时,答案是好求的。下面我们假定
,
,
。
首先发现如果我们连续做两次第一种操作或者连续做两次第二种操作,相当于没有操作。所以如果我们要产生尽可能多的情况,一定是先做操作一再做操作二不断反复。我们要求的就是做多少次后序列会恢复。
我们把先做一次操作一再做一次操作二看为“一***作”。那么答案就是序列恢复所需要做的“一***作”次数乘以 。
我们可以模拟第一次的“一***作”,得出一个新的排列 ,对于所有
,将
向
连一条有向边,形成若干环,答案就是所有环环长
乘以
。这样我们可以做到
。
分析排列 长成什么样子:
那么对于 ,它会向这个点连边:
我们可以得出一个简单的结论:我们只计算包含点 、
、
、
、
、
的环的环长的
,就可以得到答案。
当 取值不在这些点时,包含它的环的环长一定与某一个包含上面这些点的环的环长相等。这一点可以通过反证法证明。
考虑怎么快速计算包含一个点的环的环长。我们定义上面的连边情况中当 时为情况
,当
时为情况
,
时为情况
。
我们发现情况 实际上类似于将
移动到
,假如移动
步后一直都在情况
中,它将会移动到
,直到超过情况
的边界——
。相当于我们从
出发,每次走
个单位长度,问走多少步才能超过
。所以我们通过一个简单的除法计算就可以得出到达下一个不在情况
中的点所需的步数以及到达的位置。
发现:对于一个环,在情况 中的连续点数不会超过
,在情况
中的连续点数不会超过
。
证明:假如当前点是满足情况 的点
,向后移动了两个点后依旧在情况
中,那么就会移动回
,形成一个大小为
的环。所以连续点数不会超过
。情况
同理。
发现:发现连续的情况 ,连续的情况
或者连续的情况
形成的连续段最多不会超过
个。
证明:假如当前点是满足情况 的点
,向后移动了若干步后移动到满足情况
的点
,此时通过情况
移动到满足情况
的点
,再通过若干次移动移动到满足情况
的
,移动到满足情况
的
,最后通过若干次移动回
,连续段数恰好为
。其它情况可以类似证明。
综上,我们可以从点 、
、
、
、
、
开始计算包含这些点的环的环长,当点在情况
时,可以通过快速计算得到下一个不在情况
的点;当点在情况
或
时,因为最多不会超过
个点,可以直接暴力移动。最后因为连续段不会超过
,所以模拟只会进行
次。
时间复杂度 ,瓶颈在于对高精度运算与求
,精细实现可以做到更优。
from math import gcd, lcm
P = 998244353
def run(x, n, a, b):
x = ((x - 1) % n + n) % n + 1
sz = 0
tmp = x
if 1 <= tmp <= a + b - n:
sz += 1
tmp += n * 2 - a - b
elif a + b - n + 1 <= tmp <= a:
sz += 1
tmp = a + 1 - tmp
elif a + 1 <= tmp <= n:
sz += 1
tmp = n * 2 - b + 1 - tmp
while tmp != x:
if 1 <= tmp <= a + b - n:
if 1 <= x <= a + b - n and x >= tmp and (x - tmp) % (n * 2 - a - b) == 0:
step = (x - tmp) // (n * 2 - a - b)
else:
step = (a + b - n - tmp + (n * 2 - a - b)) // (n * 2 - a - b)
sz += step
tmp += step * (n * 2 - a - b)
elif a + b - n + 1 <= tmp <= a:
sz += 1
tmp = a + 1 - tmp
elif a + 1 <= tmp <= n:
sz += 1
tmp = n * 2 - b + 1 - tmp
return sz
T = int(input())
for _ in range(T):
ans = 1
n, a, b = map(int, input().split())
if a == 1 and b == 1:
print(1)
continue
if a == 1:
print(2)
continue
if b == 1:
print(2)
continue
if a + b <= n:
print(4)
continue
ans = lcm(ans, run(a, n, a, b))
ans = lcm(ans, run(a + b - n + 1, n, a, b))
ans = lcm(ans, run(n, n, a, b))
ans = lcm(ans, run(a + 1, n, a, b))
ans = lcm(ans, run(1, n, a, b))
ans = lcm(ans, run(a + b - n, n, a, b))
print((ans * 2) % P)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define P 998244353
const int maxn = 1000;
struct bign{
int d[maxn], len;
void clean() { while(len > 1 && !d[len-1]) len--; }
bign() { memset(d, 0, sizeof(d)); len = 1; }
bign(int num) { *this = num; }
bign(char* num) { *this = num; }
bign operator = (const char* num){
memset(d, 0, sizeof(d)); len = strlen(num);
for(int i = 0; i < len; i++) d[i] = num[len-1-i] - '0';
clean();
return *this;
}
bign operator = (int num){
char s[20]; sprintf(s, "%d", num);
*this = s;
return *this;
}
bign operator + (const bign& b){
bign c = *this; int i;
for (i = 0; i < b.len; i++){
c.d[i] += b.d[i];
if (c.d[i] > 9) c.d[i]%=10, c.d[i+1]++;
}
while (c.d[i] > 9) c.d[i++]%=10, c.d[i]++;
c.len = max(len, b.len);
if (c.d[i] && c.len <= i) c.len = i+1;
return c;
}
bign operator - (const bign& b){
bign c = *this; int i;
for (i = 0; i < b.len; i++){
c.d[i] -= b.d[i];
if (c.d[i] < 0) c.d[i]+=10, c.d[i+1]--;
}
while (c.d[i] < 0) c.d[i++]+=10, c.d[i]--;
c.clean();
return c;
}
bign operator * (const bign& b)const{
int i, j; bign c; c.len = len + b.len;
for(j = 0; j < b.len; j++) for(i = 0; i < len; i++)
c.d[i+j] += d[i] * b.d[j];
for(i = 0; i < c.len-1; i++)
c.d[i+1] += c.d[i]/10, c.d[i] %= 10;
c.clean();
return c;
}
bign operator / (const bign& b){
int i, j;
bign c = *this, a = 0;
for (i = len - 1; i >= 0; i--)
{
a = a*10 + d[i];
for (j = 0; j < 10; j++) if (a < b*(j+1)) break;
c.d[i] = j;
a = a - b*j;
}
c.clean();
return c;
}
bign operator % (const bign& b){
int i, j;
bign a = 0;
for (i = len - 1; i >= 0; i--)
{
a = a*10 + d[i];
for (j = 0; j < 10; j++) if (a < b*(j+1)) break;
a = a - b*j;
}
return a;
}
bign operator += (const bign& b){
*this = *this + b;
return *this;
}
bool operator <(const bign& b) const{
if(len != b.len) return len < b.len;
for(int i = len-1; i >= 0; i--)
if(d[i] != b.d[i]) return d[i] < b.d[i];
return false;
}
bool operator >(const bign& b) const{return b < *this;}
bool operator<=(const bign& b) const{return !(b < *this);}
bool operator>=(const bign& b) const{return !(*this < b);}
bool operator!=(const bign& b) const{return b < *this || *this < b;}
bool operator==(const bign& b) const{return !(b < *this) && !(b > *this);}
string str() const{
char s[maxn]={};
for(int i = 0; i < len; i++) s[len-1-i] = d[i]+'0';
return s;
}
};
istream& operator >> (istream& in, bign& x)
{
string s;
in >> s;
x = s.c_str();
return in;
}
ostream& operator << (ostream& out, const bign& x)
{
out << x.str();
return out;
}
ll T;
bign ans = 1, n, a, b;
bign gcd(bign a, bign b) {
if(b == 0) return a;
return gcd(b, a % b);
}
bign lcm(bign a, bign b) {
return a * b / gcd(a, b);
}
void run(bign x) {
x = ((x - bign(1)) % n + n) % n + bign(1);
bign sz = 0, tmp = x;
if(bign(1) <= tmp && tmp <= a + b - n) {
sz += 1;
tmp += n * bign(2) - a - b;
} else if(a + b - n + bign(1) <= tmp && tmp <= a) {
sz += 1;
tmp = a + bign(1) - tmp;
} else if(a + bign(1) <= tmp && tmp <= n) {
sz += 1;
tmp = n * 2 - b + bign(1) - tmp;
}
while(tmp != x) {
if(bign(1) <= tmp && tmp <= a + b - n) {
bign step = 0;
if(bign(1) <= x && x <= a + b - n && x >= tmp && (x - tmp) % (n * 2 - a - b) == 0) {
step = (x - tmp) / (n * bign(2) - a - b);
} else {
step = (a + b - n - tmp + (n * 2 - a - b)) / (n * bign(2) - a - b);
}
sz += step;
tmp += step * (n * bign(2) - a - b);
} else if(a + b - n + bign(1) <= tmp && tmp <= a) {
sz += 1;
tmp = a + bign(1) - tmp;
} else if(a + bign(1) <= tmp && tmp <= n) {
sz += 1;
tmp = n * 2 - b + bign(1) - tmp;
}
}
ans = lcm(ans, sz);
// cerr << sz << endl;
}
int main() {
cin >> T;
while(T --) {
ans = 1;
cin >> n >> a >> b;
if(a == 1 && b == 1) {
cout << 1 << endl;
continue;
}
if(a == 1) {
cout << 2 << endl;
continue;
}
if(b == 1) {
cout << 2 << endl;
continue;
}
if(a + b <= n) {
cout << 4 << endl;
continue;
}
run(a);
run(a + b - n + 1);
run(n);
run(a + 1);
run(1);
run(a + b - n);
cout << ans * 2 % P << endl;
}
return 0;
}