把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【2019.7.26 NOIP模拟赛 T1】数字查找(figure)(数学)

推式子

我们设\(n=kp+w\),则:

\[(kp+w)a^{kp+w}\equiv b(mod\ p) \]

将系数中的\(kp+w\)\(p\)取模,指数中的\(kp+w\)根据欧拉定理向\(p-1\)取模,得到:

\[wa^{k+w}\equiv b(mod\ p) \]

两边同除以\(wa^w\),得到:

\[a^k\equiv\frac b{wa^w}(mod\ p) \]

求答案

考虑到\(p\)很小,因此我们直接枚举\(w\),则右边式子的值可以通过预处理逆元和幂的逆元,\(O(1)\)计算出来。

那么我们就是要求出在\(0\sim\lfloor\frac {x-w}p\rfloor\)范围内存在多少个\(k\)满足\(a^k(mod\ p)\)等于我们给定的值。

由于从小往大枚举\(w\)\(k\)的上界递减,因此我们可以采用类似莫队但只有一个端点的方式去维护一个桶,总时间复杂度是\(O(p)\)的。

代码

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define LL long long
#define MxX 1000003
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
LL n;int a,b,X;
class MathSolver
{
	private:
		int pw[MxX+5],Ipw[MxX+5],Inv[MxX+5],p[MxX+5];
	public:
		I void Solve()
		{
			RI i,t=-1,lim;LL k,ans=0;
			for(Inv[1]=1,i=2;i^X;++i) Inv[i]=1LL*(X-1)*(X/i)%X*Inv[X%i]%X;//预处理逆元
			for(pw[0]=Ipw[0]=1,i=1;i^X;++i) pw[i]=1LL*pw[i-1]*a%X,Ipw[i]=1LL*Ipw[i-1]*Inv[a]%X;//预处理幂及其逆元
			for(i=0,t=n/X;i<=t;++i) ++p[pw[i%(X-1)]];//预处理桶
			for(i=1,lim=min(n,X-1);i<=lim;++i)//枚举余数
			{
				k=(n-i)/X;W(t>k) --p[pw[(t--)%(X-1)]];//移动上界
				ans+=p[1LL*b*Ipw[i%(X-1)]%X*Inv[i]%X];//统计答案
			}printf("%lld",ans);//输出答案
		}
}S;
int main()
{
	freopen("figure.in","r",stdin),freopen("figure.out","w",stdout);
	return scanf("%d%d%d%lld",&a,&b,&X,&n),a%=X,b%=X,S.Solve(),0;
}
posted @ 2019-07-27 08:11  TheLostWeak  阅读(191)  评论(0编辑  收藏  举报