题目链接
一、题意
有一个未知数,满足。
现在有一个集合
你知道,想通过总数不超过次以下操作知道。
有如下三种操作:
:询问的倍数有几个。
:询问的倍数有几个。然后把的所有倍数从集合中删除,注意不会从集合中删除。
:输出答案,。
数据范围:
二、题解
首先打个表发现不超过的素数有个,很接近询问的上限。
考虑分块。
设不超过的素数有个,每块有个素数。
每次用第2种操作询问个素数,也就是删除操作。维护,表示认为可以删除,集合中剩余的数。
在对一整块数进行删除操作后,用第一种操作询问,用表示的倍数的剩余个数,也就是集合中剩余数的个数。
如果该块素数都不是的因子,那么。
重复操作,直到在一块数在进行删除操作后出现。
我们已经知道的最小因子在哪一块中,并且认为已经被删除。
那么我们可以对之后的每一个素数进行第一种操作,是枚举的素数。
在知道时可以停止对的询问。
我们可以知道,满足。
三、代码
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << #x << " = " << x << '\n'
#define ddebug(x , y) cerr << #x << " = " << x << " " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
vector<int> p ;
struct Easymath
{
ll qpow(ll a , ll b) //快速幂
{
if(b < 0) return 0 ;
ll ans = 1 ;
a %= mod ;
while(b)
{
if(b & 1) ans = (ans * a) % mod ;
b >>= 1 , a = (a * a) % mod ;
}
return ans % mod ;
}
ll ksc_log(ll x , ll y , ll mod) //快速乘
{
x %= mod , y %= mod ;
ll ans = 0;
while(y)
{
if(y & 1) ans = (ans + x) % mod ;
y >>= 1 ;
x = (x + x) % mod ;
}
return ans;
}
ll ksc_O1(ll x , ll y , ll mod) //快速乘
{
x %= mod , y %= mod ;
ll z = (ld)x * y / mod ;
ll ans = x * y - z * mod ;
if(ans < 0) ans += mod ;
else if(ans >= mod) ans -= mod ;
return ans ;
}
int cnt = 0 ;
bool vis[maxn] ;
int prime[maxn] ;
void get_prime(int up) //素数筛
{
memset(vis , 0 , sizeof(vis)) ;
vis[1] = 1 ;
for(int i = 2 ; i <= up ; i ++)
{
if(!vis[i]) prime[++ cnt] = i , p.pb(i) ;
for(int j = 1 ; j <= cnt && i * prime[j] <= up ; j ++)
{
vis[i * prime[j]] = 1 ;
if(i % prime[j] == 0) break ;
}
}
}
//begin 判定大素数
ll mul(ll a , ll b , ll mod)
{
ll ret = 0 ;
while(b)
{
if(b & 1) ret = (ret + a) % mod ;
a = (a + a) % mod ;
b >>= 1 ;
}
return ret ;
}
ll pow(ll a , ll b , ll mod)
{
ll ret = 1 ;
while(b)
{
if(b & 1) ret = mul(ret , a , mod) ;
a = mul(a , a , mod) ;
b >>= 1 ;
}
return ret ;
}
bool check(ll a , ll n)
{
ll x = n - 1 ;
int t = 0 ;
while((x & 1) == 0)
{
x >>= 1 ;
t ++ ;
}
x = pow(a , x , n) ;
ll y ;
rep(i , 1 , t)
{
y = mul(x , x , n) ;
if(y == 1 && x != 1 && x != n - 1) return 1 ;
x = y ;
}
if(y != 1) return 1 ;
return 0 ;
}
bool Miller_Rabin(ll n)
{
if(n == 2) return 1 ;
if(n == 1 || !(n & 1)) return 0 ;
const int arr[12] = {2,3,5,7,11,13,17,19,23,29,31,37} ;
rep(i , 0 , 11)
{
if(arr[i] >= n) break ;
if(check(arr[i] , n)) return 0 ;
}
return 1 ;
}
//end 判定大素数
ll get_inv(ll x) //逆元
{
return qpow(x , mod - 2) % mod ;
}
ll inv1[maxn] ; //乘法逆元
void init1(int up)
{
inv1[1] = 1 ;
for(int i = 2 ; i <= up ; i ++)
inv1[i] = (ll)(mod - mod / i) * inv1[int(mod % (ll)i)] % mod ;
}
ll fac[maxn] ;
ll inv[maxn] ; //阶乘逆元
void init(int up)
{
fac[0] = fac[1] = inv[0] = inv[1] = 1 ;
for(int i = 2 ; i <= up ; i ++)
{
fac[i] = fac[i - 1] * i % mod ;
inv[i] = -inv[mod % i] * (mod / i) % mod ;
while(inv[i] < 0) inv[i] += mod ;
}
for(int i = 2 ; i <= up ; i ++)
inv[i] = inv[i] * inv[i - 1] % mod ;
}
ll C(int n , int m)
{
return fac[n] * inv[m] % mod * inv[n - m] % mod ;
}
} em ;
bool used[maxn] ;
int ask(int i)
{
printf("A %d\n" , i) ;
fflush(stdout) ;
int x ;
scanf("%d" , &x) ;
return x ;
}
int del(int i)
{
printf("B %d\n" , i) ;
fflush(stdout) ;
int x ;
scanf("%d" , &x) ;
return x ;
}
int main()
{
int n ;
scanf("%d" , &n) ;
em.get_prime(n) ;
int cnt = em.cnt ;
int blk = sqrt(cnt) ;
int ans = 1 ;
int res = n ;
int siz = cnt - 1 ;
int tmp = n + 1 ;
rep(i , 0 , siz)
{
int nxt = i + blk - 1 ;
nxt = min(nxt , siz) ;
rep(j , i , nxt)
{
int x = p[j] ;
del(x) ;
for(int k = x ; k <= n ; k += x) if(!used[k]) used[k] = 1 , res -- ;
}
int num = ask(1) ;
if(num != res)
{
tmp = i ;
break ;
}
i = nxt ;
}
rep(i , tmp , siz)
{
int x = p[i] ;
int res = 0 ;
if(ans * x > n) break ;
for(ll k = x ; k <= n ; k *= x) if(!used[k]) res ++ ;
for(ll k = x ; k <= n ; k *= x)
{
int num = ask(k) ;
if(num != res) ans *= x ;
else break ;
if(!used[k]) res -- ;
}
}
printf("C %d\n" , ans) ;
fflush(stdout) ;
return 0 ;
}