LG-P5285 [十二省联考 2019] 骗分过样例 题解
LG-P5285 [十二省联考 2019] 骗分过样例
更好的阅读体验戳此进入
(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)
十分奇怪的一道题,不过其中涉及到的很多知识点却又是很实用的。
题意描述的已经很清楚了,这里对于每类点分别写一个 namespace
并分别讲解。
Default
这些是本题很多地方需要用到的一些函数,这里我把它们封装到一起:
namespace Default{
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
template<typename T = int>
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
ll readBignum(ll MOD){
ll ret(0);
char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c)){
ret = (ret * 10 + int(c - '0')) % MOD;
c = getchar();
}
return ret;
}
ll readBignum(ll MOD, string num){
ll ret(0);
for(auto c : num){
if(!isdigit(c))continue;
ret = (ret * 10 + int(c - '0')) % MOD;
}
return ret;
}
ll qmul(ll x, ll y, ll MOD){
return (__int128_t)x * y % MOD;
// ll quot = (ld)x / MOD * y;
// ll ret = (unll)x * y - (unll)quot * MOD;
// return (ret + MOD) % MOD;
}
ll qpow(ll a, ll b, ll MOD){
ll ret(1), mul(a);
while(b){
if(b & 1)ret = qmul(ret, mul, MOD);
b >>= 1;
mul = qmul(mul, mul, MOD);
}
return ret;
}
bool MillerRabin(ll n, bool special = false){
int prime[20] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
if(n % 2 == 0 || n <= 2)return n == 2;
ll power(n - 1); int cnt(0);
while(power % 2 == 0)power /= 2, ++cnt;
int times = special ? 1 : 12;
while(times--){
if(n == prime[times + 1])return true;
ll base = prime[times + 1], res = qpow(base, power, n);
ll nxt;
// if(res == n - 1 || res == 1)continue;
for(int i = 1; i <= cnt; ++i){
nxt = qmul(res, res, n);
if(nxt == 1 && res != 1 && res != n - 1)return false;
res = nxt;
}
if(nxt != 1)return false;
}
return true;
}
}
下面对这些函数的作用进行简单说明:
mt19937 rnd(random_device{}());
int rndd(int l, int r);
随机数生成器。
template<typename T>
inline T read(void);
标准的快读模板。
ll readBignum(ll MOD);
ll readBignum(ll MOD, string num);
读入一些特别长的数,并在读入过程中取模。
ll qpow(ll a, ll b, ll MOD);
快速幂模板。
ll smul(ll x, ll y, ll MOD);
快速乘模板,用 __int128_t
实现。
bool MillerRabin(ll n, bool special = false);
用于快速判定是否为素数,关于 Miller Rabin。
Case 1~3
简单观察发现输入为 $ 0, 1, 2, 3, \cdots $。
输出为 $ 1, 19, 361, 6859, \cdots $。
显然为 $ 19^0, 19^1, 19^2, 19^3, \cdots $。
所以显然这个功能即为输入 $ x $ 输出 $ 19^x $。
然后观察文件名发现其中有 998244353
字段,十分显然就是对其取模,即求的是 $ 19^x \bmod{998244353} $。
对于前两个点简单的快速幂就能过,而对于第三个点发现 $ x $ 很大,所以需要用到欧拉定理:
若 $ p $ 为素数,则有 $ a^{p - 1} \equiv 1 \pmod{p} $。
简单转化一下,令 $ 19^x \bmod{998244353} = \xi $ 则有:
所以对于这三个点丢可以直接输出 $ 19^{x \bmod{p - 1}} \bmod{998244353} $。
同时发现 $ x $ 超过 long long
了,于是我们需要在读入的时候边读入边取模。
namespace Case_1_2_3{
void Make(ll MOD = 998244353){
int N = Default::read();
for(int i = 1; i <= N; ++i){
ll x = Default::readBignum(MOD - 1);
printf("%lld\n", Default::qpow(19, x, MOD));
}
}
}
Case 4
观察文件名发现,区别只是模数变成了 ?
,于是这也很显然,我们需要确定模数。
观察样例,我们发现以下几个性质:
- 枚举的下界要比答案中所有数大,即 $ 1145099 + 1 $,这个数可以手动找也可以写个程序,把输入定向到这个文件,然后找一下最大值,当然这个性质不考虑的话,
嗯枚举似乎也不会耗费太久的时间(可能吧? - 虽然题里没说,但是我们可以假定这个模数一定为质数
要不然就太毒瘤了。 - 对于判断一个数是否为质数可以直接用 MillerRabin。
- 判断找的模数对不对可以考虑直接用第一个大数验证一下即可,也就是 $ 627811703016764290815178977207148434322 \Longrightarrow 642666 $。
于是写出枚举找素数的程序:
namespace Case_4{
ll FindMod(void){
string val_s("627811703016764290815178977207148434322");
ll std_res = 642666;
for(ll i = 1145099 + 1; i <= LLONG_MAX; ++i){
if(i % 2 == 0 || !Default::MillerRabin(i))continue;
ll val = Default::readBignum(i - 1, val_s);
ll res = Default::qpow(19, val, i);
if(res == std_res)return i;
}
}
void Make(void){
Case_1_2_3::Make(1145141ll);
}
}
跑一下就可以得到素数为 $ 1145141 $。
Case 5
既然是升级版肯定不会让你这么简单枚举出来模数的
有一个很人类智慧的枚举方法,对于整个输入输出,我们要找到一对最接近的 $ x, y \quad x \lt y $,且对于答案有 $ ans_x > ans_y $。
这时简单想一下就会发现可以通过 $ x $ 的答案推出来没有取模完全的 $ y $ 的答案,也就是:$ ans_x \times 19^{y - x} \equiv ans_y \pmod{p} $。
或者写成:$ ans_x \times 19^{y - x} \bmod{p} = ans_y $。
所以显然这个时候我们需要枚举的模数就只可能是 $ ans_x \times 19^{y - x} - ans_y $ 的因数。
思路大概这样,实现就不写了,只需要注意两个点:
- 首先为了这道题比较可做,模数应该会在
long long
范围内,我们也只需要在此范围内枚举。 - 然后和之前一样,我们是存在枚举下界的,就是答案中最大的数加一,可以在跑 $ x, y $ 的时候顺便把下界跑出来。
总之最后得出来的结果应该是:
模数是 $ 719200885258981741674 $ 的因数,模数下界是 $ 5211500658258874319 $,最终计算得出模数为 $ 5211600617818708273 $。
namespace Case_5{
void Make(void){
Case_1_2_3::Make(5211600617818708273ll);
}
}
Case 6~7
观察文件名发现序号没变,那么求的东西不变,然后观察文件名里有 wa
,输出的答案里有负数,又联想到提示里的内容,所以显然这个是因为 int
溢出了所以变成负数。
然后我们感性理解一下,模意义下的很多模数都是一个群,从群的角度感性理解一下这个溢出应该也会有周期性,所以我们可以通过 map < int, int >
来找第一个重复出现的数,也就是周期。
大概的实现是这样:
namespace Case_6_7{
const int MOD(998244353);
int ans[11000000];
int beg(-1), siz(-1);
void FindCirc(void){
map < int, int > mp;
int base(1);
mp.insert({ans[0] = base, 0});
for(int i = 1; true; ++i){
if(mp.find(base = signed((unsigned)base * (unsigned)19) % MOD) != mp.end()){beg = mp[base], siz = i - mp[base]; return;}
else mp.insert({ans[i] = base, i});
}
}
void Make(void){
FindCirc();
int N = Default::read();
for(int i = 1; i <= N; ++i){
ll x = Default::read<ll>();
if(x < beg)printf("%d\n", ans[x]);
else printf("%d\n", ans[(x - beg) % siz + beg]);
}
}
}
Case 8~10
序号变为 $ 2 $,所以显然要实现的功能改变了,观察文件名 p
显然代表着 Prime,简单看一下样例就能明白要实现的是对于 $ \left[l, r\right] $ 的数,质数输出 p
,合数输出 .
,简单用 Miller-Rabin 判一下即可。
namespace Case_8_9_10{
void Make(void){
int N = Default::read();
for(int i = 1; i <= N; ++i){
ll l = Default::read<ll>(), r = Default::read<ll>();
for(ll x = l; x <= r; ++x){
printf("%c", Default::MillerRabin(x) ? 'p' : '.');
}
printf("\n");
}
}
}
Case 11~13
观察文件名 u
显然是求莫比乌斯函数,对于第一个点显然打个线性筛就行,具体看这里。
第二第三个点可以理解为求任意区间内的莫比乌斯函数,可以考虑把值域分一下,预处理出 $ (10{18}){3}} = 10^6 $ 以内的莫比乌斯函数和质数,然后在要求的区间内筛一下,把每个数中的 $ 10^6 $ 以内的质因子全部除下去,然后在除的时候注意维护莫比乌斯函数,特判一下如果有平方因子变成零就行,相信你们都会。
然后显然对于区间内最后剩下的数一定是一下几个情况:
- 本身就是一个质数,可以用 Miller-Rabin 判定,此时 $ \mu = -1 $。
- 是某个大于 $ 10^6 $ 质数的完全平方,此时 $ \mu = 0 $。
- 是两个大于 $ 10^6 $ 不同质数的乘积,此时 $ \mu = 1 $。
这里如果 $ \mu $ 已经为 $ 0 $ 或剩下的数已经为 $ 1 $ 了则可以不用讨论,是个小剪枝。
不过这题 Luogu 上卡常很离谱, $ 12, 13 $ 很难卡过,有一个很不严谨的卡常,通过面向数据剪枝我们可以发现如果把求莫比乌斯函数时候的 Miller-Rabin 测试次数设置为 $ 1 $,只测试底数为 $ 2 $,刚好可以把数据卡过不影响正确性,于是可以卡常过 Luogu,在 LOJ 上评测机比较快可以不用考虑这一点。
namespace Case_11_12_13{
#define PRE (ll)(1e6)
#define RPOS beg - l + 1
void Make(void){
vector < int > prime;
bool vis[PRE + 10];
int mu[PRE + 10];
vis[1] = true, mu[1] = 1;
for(int i = 2; i <= PRE; ++i){
if(!vis[i]){
vis[i] = true;
mu[i] = -1;
prime.push_back(i);
}
for(auto p : prime){
if(p * i > PRE)break;
vis[p * i] = true;
mu[p * i] = i % p == 0 ? 0 : -mu[i];
if(i % p == 0)break;
}
}
int N = Default::read();
while(N--){
ll l = Default::read<ll>(), r = Default::read<ll>();
if(r <= PRE){
for(int i = l; i <= r; ++i){
printf("%c", mu[i] == 1 ? '+' : (mu[i] == -1 ? '-' : '0'));
}
printf("\n");
continue;
}
int siz = r - l + 1;
ll value[1100000];
for(int i = 1; i <= siz; ++i)value[i] = (ll)i + l - 1;
int mu_r[1100000];
memset(mu_r, 0x3f, sizeof(mu_r));
for(auto p : prime){
ll times = l / p;
ll beg = p * times;
while(beg < l)beg += p;
while(beg <= r){
value[RPOS] /= p;
if(value[RPOS] % p == 0)mu_r[RPOS] = 0;
mu_r[RPOS] = mu_r[RPOS] > 1 ? -1 : -mu_r[RPOS];
beg += p;
}
}
for(int i = 1; i <= siz; ++i){
if(mu_r[i] == 0 || value[i] == 1)continue;
if(Default::MillerRabin(value[i], true))mu_r[i] = mu_r[i] > 1 ? -1 : -mu_r[i];
else if(value[i] != 1 && (ll)sqrt(value[i]) * (ll)sqrt(value[i]) == value[i])mu_r[i] = 0;
else if(mu_r[i] > 1)mu_r[i] = 1;
}
for(int i = 1; i <= siz; ++i)printf("%c", mu_r[i] == 1 ? '+' : (mu_r[i] == -1 ? '-' : mu_r[i] == 0 ? '0' : '?'));
printf("\n");
}
}
}
Case 14~16
观察文件名 g
显然是要求区间内的数是否为原根。对于第一个点模数全为 $ 998244353 $,区间不是很大,直接把 $ \phi(998244353) $ 质因数分解然后对于区间内每一个数跑一遍暴力验证即可。即:
对于其所有质因数 $ frac(i) $ 有 $ g^{\frac{\phi(MOD)}{frac(i)}} \neq 1 $。
对于第二个点多了一个 $ 13123111 $,且区间较大,不能暴力跑,于是考虑有如下性质:
对于原根 $ g $, $ g^x \pmod{MOD} $ 为原根当且仅当 $ x \perp \phi(MOD) $,这个 $ x $ 似乎叫做指标。
可以考虑把其分解质因数,标记所有其质因数的区间内的倍数,也就是筛一下,最终所有没有标记的数可以表示为 $ g^x $ 的即为原根。
然后对于最后一个点,和之前的思路一样,显然模数是质数,把模数枚举一下,然后选二十个左右的数据,随便选一个质因子验证一下,很快就能跑出来模数为 $ 1515343657 $。
namespace Case_14_15_16{
#define PRE (int)(1e6)
vector < ll > prime;
bool vis[PRE + 100];
void Pretreat(void){
vis[1] = true;
for(int i = 2; i <= PRE; ++i){
if(!vis[i])prime.push_back(i), vis[i] = true;
for(auto p : prime){
if(p * i > PRE)break;
vis[p * i] = true;
if(i % p == 0)break;
}
}
}
vector < ll > Resolve(ll x){
#ifndef PRETREAT
#define PRETREAT
Pretreat();
#endif//PRETREAT
vector < ll > ret;
for(auto p : prime){
if(p * p > x)break;
if(x % p == 0)ret.push_back(p);
while(x % p == 0)x /= p;
}
if(x != 1)ret.push_back(x);
return ret;
}
map < ll, ll > mp;
ll FindMinG(ll x){
if(mp.find(x) != mp.end())return mp[x];
vector < ll > fact = Resolve(x - 1);
for(ll i = 2; i <= (ll)pow(x, 0.25); ++i){
bool flag(true);
for(auto p : fact){
if(Default::qpow(i, (x - 1) / p, x) == 1){flag = false; break;}
}
if(flag){
mp.insert({x, i});
return i;
}
}
return -1;
}
void Make(void){
int N = Default::read();
for(int i = 1; i <= N; ++i){
ll l = Default::read<ll>(), r = Default::read<ll>();
ll MOD = l != 233333333ll ? Default::read<ll>() : 1515343657ll;
if(MOD == 998244353ll || MOD == 1515343657ll){
vector < ll > frac = Resolve(MOD - 1);
for(ll x = l; x <= r; ++x){
bool flag(true);
for(auto p : frac)
if(Default::qpow(x, (MOD - 1) / p, MOD) == 1){printf("."); flag = false; break;}
if(flag)printf("g");
}
printf("\n");
continue;
}
vector < ll > frac = Resolve(MOD - 1);
ll G = FindMinG(MOD);//fprintf(stderr, "G: %lld\n", G);
#define CMOD (13123111)
bool mark[CMOD + 100];
for(auto p : frac)
for(ll j = 1; j * p <= CMOD; ++j)
mark[j * p] = true;
int logg[CMOD + 100];
memset(logg, 0, sizeof(logg));
for(ll cur(1), base(0); base <= CMOD; ++base, cur = cur * G % CMOD)
logg[cur] = base;
for(ll x = l; x <= r; ++x)
printf("%c", mark[logg[x]] ? '.' : 'g');
printf("\n");
}
}
}
AC Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
namespace Default{
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
template<typename T = int>
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
ll readBignum(ll MOD){
ll ret(0);
char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c)){
ret = (ret * 10 + int(c - '0')) % MOD;
c = getchar();
}
return ret;
}
ll readBignum(ll MOD, string num){
ll ret(0);
for(auto c : num){
if(!isdigit(c))continue;
ret = (ret * 10 + int(c - '0')) % MOD;
}
return ret;
}
ll qmul(ll x, ll y, ll MOD){
return (__int128_t)x * y % MOD;
// ll quot = (ld)x / MOD * y;
// ll ret = (unll)x * y - (unll)quot * MOD;
// return (ret + MOD) % MOD;
}
ll qpow(ll a, ll b, ll MOD){
ll ret(1), mul(a);
while(b){
if(b & 1)ret = qmul(ret, mul, MOD);
b >>= 1;
mul = qmul(mul, mul, MOD);
}
return ret;
}
bool MillerRabin(ll n, bool special = false){
int prime[20] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
if(n % 2 == 0 || n <= 2)return n == 2;
ll power(n - 1); int cnt(0);
while(power % 2 == 0)power /= 2, ++cnt;
int times = special ? 1 : 12;
while(times--){
if(n == prime[times + 1])return true;
ll base = prime[times + 1], res = qpow(base, power, n);
ll nxt;
// if(res == n - 1 || res == 1)continue;
for(int i = 1; i <= cnt; ++i){
nxt = qmul(res, res, n);
if(nxt == 1 && res != 1 && res != n - 1)return false;
res = nxt;
}
if(nxt != 1)return false;
}
return true;
}
}
namespace Case_1_2_3{
void Make(ll MOD = 998244353){
int N = Default::read();
for(int i = 1; i <= N; ++i){
ll x = Default::readBignum(MOD - 1);
printf("%lld\n", Default::qpow(19, x, MOD));
}
}
}
namespace Case_4{
ll FindMod(void){
string val_s("627811703016764290815178977207148434322");
ll std_res = 642666;
for(ll i = 1145099 + 1; i <= LLONG_MAX; ++i){
if(i % 2 == 0 || !Default::MillerRabin(i))continue;
ll val = Default::readBignum(i - 1, val_s);
ll res = Default::qpow(19, val, i);
if(res == std_res)return i;
}
}
void Make(void){
Case_1_2_3::Make(1145141ll);
}
}
namespace Case_5{
void Make(void){
Case_1_2_3::Make(5211600617818708273ll);
}
}
namespace Case_6_7{
const int MOD(998244353);
int ans[11000000];
int beg(-1), siz(-1);
void FindCirc(void){
map < int, int > mp;
int base(1);
mp.insert({ans[0] = base, 0});
for(int i = 1; true; ++i){
if(mp.find(base = signed((unsigned)base * (unsigned)19) % MOD) != mp.end()){beg = mp[base], siz = i - mp[base]; return;}
else mp.insert({ans[i] = base, i});
}
}
void Make(void){
FindCirc();
int N = Default::read();
for(int i = 1; i <= N; ++i){
ll x = Default::read<ll>();
if(x < beg)printf("%d\n", ans[x]);
else printf("%d\n", ans[(x - beg) % siz + beg]);
}
}
}
namespace Case_8_9_10{
void Make(void){
int N = Default::read();
for(int i = 1; i <= N; ++i){
ll l = Default::read<ll>(), r = Default::read<ll>();
for(ll x = l; x <= r; ++x){
printf("%c", Default::MillerRabin(x) ? 'p' : '.');
}
printf("\n");
}
}
}
namespace Case_11_12_13{
#define PRE (ll)(1e6)
#define RPOS beg - l + 1
void Make(void){
vector < int > prime;
bool vis[PRE + 10];
int mu[PRE + 10];
vis[1] = true, mu[1] = 1;
for(int i = 2; i <= PRE; ++i){
if(!vis[i]){
vis[i] = true;
mu[i] = -1;
prime.push_back(i);
}
for(auto p : prime){
if(p * i > PRE)break;
vis[p * i] = true;
mu[p * i] = i % p == 0 ? 0 : -mu[i];
if(i % p == 0)break;
}
}
int N = Default::read();
while(N--){
ll l = Default::read<ll>(), r = Default::read<ll>();
if(r <= PRE){
for(int i = l; i <= r; ++i){
printf("%c", mu[i] == 1 ? '+' : (mu[i] == -1 ? '-' : '0'));
}
printf("\n");
continue;
}
int siz = r - l + 1;
ll value[1100000];
for(int i = 1; i <= siz; ++i)value[i] = (ll)i + l - 1;
int mu_r[1100000];
memset(mu_r, 0x3f, sizeof(mu_r));
for(auto p : prime){
ll times = l / p;
ll beg = p * times;
while(beg < l)beg += p;
while(beg <= r){
value[RPOS] /= p;
if(value[RPOS] % p == 0)mu_r[RPOS] = 0;
mu_r[RPOS] = mu_r[RPOS] > 1 ? -1 : -mu_r[RPOS];
beg += p;
}
}
for(int i = 1; i <= siz; ++i){
if(mu_r[i] == 0 || value[i] == 1)continue;
if(Default::MillerRabin(value[i], true))mu_r[i] = mu_r[i] > 1 ? -1 : -mu_r[i];
else if(value[i] != 1 && (ll)sqrt(value[i]) * (ll)sqrt(value[i]) == value[i])mu_r[i] = 0;
else if(mu_r[i] > 1)mu_r[i] = 1;
}
for(int i = 1; i <= siz; ++i)printf("%c", mu_r[i] == 1 ? '+' : (mu_r[i] == -1 ? '-' : mu_r[i] == 0 ? '0' : '?'));
printf("\n");
}
}
#undef PRE
#undef RPOS
}
namespace Case_14_15_16{
#define PRE (int)(1e6)
vector < ll > prime;
bool vis[PRE + 100];
void Pretreat(void){
vis[1] = true;
for(int i = 2; i <= PRE; ++i){
if(!vis[i])prime.push_back(i), vis[i] = true;
for(auto p : prime){
if(p * i > PRE)break;
vis[p * i] = true;
if(i % p == 0)break;
}
}
}
vector < ll > Resolve(ll x){
#ifndef PRETREAT
#define PRETREAT
Pretreat();
#endif//PRETREAT
vector < ll > ret;
for(auto p : prime){
if(p * p > x)break;
if(x % p == 0)ret.push_back(p);
while(x % p == 0)x /= p;
}
if(x != 1)ret.push_back(x);
return ret;
}
map < ll, ll > mp;
ll FindMinG(ll x){
if(mp.find(x) != mp.end())return mp[x];
vector < ll > fact = Resolve(x - 1);
for(ll i = 2; i <= (ll)pow(x, 0.25); ++i){
bool flag(true);
for(auto p : fact){
if(Default::qpow(i, (x - 1) / p, x) == 1){flag = false; break;}
}
if(flag){
mp.insert({x, i});
return i;
}
}
return -1;
}
void Make(void){
int N = Default::read();
for(int i = 1; i <= N; ++i){
ll l = Default::read<ll>(), r = Default::read<ll>();
ll MOD = l != 233333333ll ? Default::read<ll>() : 1515343657ll;
if(MOD == 998244353ll || MOD == 1515343657ll){
vector < ll > frac = Resolve(MOD - 1);
for(ll x = l; x <= r; ++x){
bool flag(true);
for(auto p : frac)
if(Default::qpow(x, (MOD - 1) / p, MOD) == 1){printf("."); flag = false; break;}
if(flag)printf("g");
}
printf("\n");
continue;
}
vector < ll > frac = Resolve(MOD - 1);
ll G = FindMinG(MOD);//fprintf(stderr, "G: %lld\n", G);
#define CMOD (13123111)
bool mark[CMOD + 100];
for(auto p : frac)
for(ll j = 1; j * p <= CMOD; ++j)
mark[j * p] = true;
int logg[CMOD + 100];
memset(logg, 0, sizeof(logg));
for(ll cur(1), base(0); base <= CMOD; ++base, cur = cur * G % CMOD)
logg[cur] = base;
for(ll x = l; x <= r; ++x)
printf("%c", mark[logg[x]] ? '.' : 'g');
printf("\n");
}
}
}
int main(){
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
string filename; cin >> filename;
if(!filename.compare("1_998244353"))Case_1_2_3::Make();
if(!filename.compare("1?"))Case_4::Make();
if(!filename.compare("1?+"))Case_5::Make();
if(!filename.compare("1wa_998244353"))Case_6_7::Make();
if(!filename.compare("2p"))Case_8_9_10::Make();
if(!filename.compare("2u"))Case_11_12_13::Make();
if(!filename.compare("2g") || ! filename.compare("2g?"))Case_14_15_16::Make();
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
UPD
update-2022_09_20 初稿