題解 Codeforces 1994H Fortnite

Meatherm發表於2024-07-19

首先第一次詢問肯定是問 \(\texttt{aa}\),答案減去 \(1\) 得到基數 \(p\)

然後我們隨意詢問一個真實 Hash 值(取模之前)\(X\) 大於模數 \(m\) 的字串,例如 \(s=\texttt{zzz}\cdots\texttt{zzz}\)\(50\)\(\texttt z\))。設它取模得到的 Hash 值是 \(a\)

考慮正整數 \(1 \leq b \leq a+1\)。注意到 \((X-a-b) \bmod m= ((X-a) \bmod m + (m-b)) \bmod m = m-b\),因為 \(a < m\)

這一步注意力非常集中!

那麼我們只要能找到 Hash 值在 \([X-1-2a,X-1-a]\) 之間的字串就結束了。

首先將 \(s_1\) 減去 \(1\),並令 \(b\)\(1\)。然後從低到高遍歷 \(s\) 的每一位,並計算 \(a\) 在這一位上的大小 \(v\)

如果 \(v\) 不超過 \(24\),那麼 \(s\) 的這一位必然可以減去 \(v\),因為 \(s_i\) 最開始是 \(\texttt{z}(26)\),就算之前被減去了 \(1\),還剩下 \(25\)

如果 \(v\) 超過了 \(24\),那麼 \(s\) 的下一位減去 \(1\),這樣會讓 \(b\) 增加 \((p-v)\times W\),其中 \(W\) 是這一位的位權。

我們注意到 \(p \leq 50\),因為 \(p-v \leq 25\),從而當 \(v = 25\) 的時候 \((p-v) \times W\) 取得最大值 $ = 25W$。因此,就算這個過程中 \((p-v) \times W\) 一直取得最大值,\(b\) 在這個過程中也不會增加一個超過 \(a\) 的量,因此 \(b\) 最多為 \(a+1\),這使得我們的構造成立。

# include <bits/stdc++.h>

const int N=100010,INF=0x3f3f3f3f;

inline void solve(void){
	std::cout<<"? aa"<<std::endl;
	int p;
	std::cin>>p;
	--p;
	
	std::string s(50,'z');
	std::cout<<"? "<<s<<std::endl;
	
	int a,b=1;
	std::cin>>a;
	--s[0];
	for(long long i=0,base=1;a>=base;++i,base*=p){
		int v=(a/base)%p;
		if(v<=24) s[i]-=v;
		else --s[i+1],b+=base*(p-v);
	}
	std::cout<<"? "<<s<<std::endl;
	int c;
	std::cin>>c;
	std::cout<<"! "<<p<<" "<<b+c<<std::endl;
	return;
}

int main(void){
	int T;
	std::cin>>T;
	while(T--) solve();
	return 0;
}

相關文章