NOIP2023模拟15联测36 数字变换

题目大意

你有一个质数 p p p和一个二元组 ( a , b ) (a,b) (a,b),它们的和不被 p p p整除。

你想对这个二元组进行若干次操作,让它们变成另外一个二元组。每一步,你可以对二元组做如下操作中的一个:

  • ( a , b ) (a,b) (a,b)变成 ( 2 a   m o d   p , ( b + p − a )   m o d   p ) (2a\bmod p,(b+p-a)\bmod p) (2amodp,(b+pa)modp)
  • ( a , b ) (a,b) (a,b)变成 ( ( a + p − b )   m o d   p , 2 b   m o d   p ) ((a+p-b)\bmod p,2b\bmod p) ((a+pb)modp,2bmodp)

你需要回答 q q q次询问,每次询问,给你 ( a i , b i , c i , d i ) (a_i,b_i,c_i,d_i) (ai,bi,ci,di),问最少需要多少步才能将 ( a i , b i ) (a_i,b_i) (ai,bi)变成 ( c i , d i ) (c_i,d_i) (ci,di)。如果不可行,则输出 − 1 -1 1

p ≤ 1 0 9 + 7 , 1 ≤ q ≤ 1 0 5 , 0 ≤ a i , b i , c i , d i ≤ p − 1 , p ∤ ( a i + b i ) p\leq 10^9+7,1\leq q\leq 10^5,0\leq a_i,b_i,c_i,d_i\leq p-1,p\nmid (a_i+b_i) p109+7,1q105,0ai,bi,ci,dip1,p(ai+bi)


题解

t = a + b t=a+b t=a+b,我们发现在操作时 t   m o d   p t\bmod p tmodp是不变的。先判断 a + b a+b a+b c + d c+d c+d   m o d   p \bmod p modp的意义下是否相同,如果不同则无解。

如果相同,则 a = c , b = d a=c,b=d a=c,b=d等价于 a = c a=c a=c。一次操作中, a a a要么变成 2 a 2a 2a,要么变成 2 a − t 2a-t 2at

所以 k k k次操作后, a a a就会变成 2 k a − q t 2^ka-qt 2kaqt,其中 q q q可以为 [ 0 , 2 k ) [0,2^k) [0,2k)中的任意值。显然 2 k ≥ p 2^k\geq p 2kp时一定有解。

所以我们只需要枚举 k k k,判断 2 k a − c t \dfrac{2^ka-c}{t} t2kac   m o d   p \bmod p modp意义下是否 < 2 k <2^k <2k即可。

时间复杂度为 O ( q log ⁡ p ) O(q\log p) O(qlogp)

code

#include
using namespace std;
int ans;
long long p,q,a,b,c,d,t;
long long mi(long long t,long long v){
	if(!v) return 1;
	long long re=mi(t,v/2);
	re=re*re%p;
	if(v&1) re=re*t%p;
	return re;
}
int main()
{
	scanf("%lld%lld",&p,&q);
	while(q--){
		scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
		t=(a+b)%p;
		if((a+b)%p!=(c+d)%p){
			printf("-1\n");continue;
		}
		long long v=1,ny=mi(t,p-2);
		for(ans=0;;v=v*2,ans++){
			long long tmp=a*v;
			if((tmp-c+p)%p*ny%p<v) break;
		}
		printf("%d\n",ans);
	}
	return 0;
}

你可能感兴趣的:(题解,题解,c++)