Loading

题解—简单的玄学

考场上推出来式子之后为了想怎么约分花了很长时间。
其实真的是,时间一长就误入歧途了。

看到取模之后的分数不唯一的那一刻心态很崩。
因为只想到了一个分数约不约分取模之后是相同的,没想到有很多分数都可以取出来这个值。
想了半天如何优化取模的操作,最后搞了一个自己感觉还行的方法。
然后暴\(0\)了。

如何保持心态也是一个问题,其实看到分数不唯一,还是半个小时,要是仔细思考,拿回来\(70pts\)也不是问题。
还有就是真的不要死磕一个方法了,真的不要了。

题解约分的方法

首先先证明一个东西。

对于\(1<a<=2^n\)\(a\)\(2\)的个数和\(2^n-a\)里面一样
很显然,因为\(2^n\)里面的\(2\)\(a\)里面多,所以肯定不会影响\(a\)提取出来\(2\)

\(m\)小于模数的时候,直接暴力扫一遍分子,然后约掉所有的\(2\),同时记录一下,约掉分母的\(2\)
只要用那个东西把数转化成可表示的就行了,因为那些数在取模意义下是等效的。
注意一下\(n*m\)过大会爆,所以我先算出来快速幂,在乘逆元。

如果\(m\)大于模数,直接\(log\)求解一个阶乘里面有多少个\(2\),和分母约掉就行了。
具体方法是\(\sum N/i\)\(i\)每次乘\(2\),因为我们要看这一段数中有多少个\(2\)的倍数,然后他们会对答案贡献\(1\)
有多少个\(4\)的倍数,因为他们会对答案额外贡献\(1\)
以此类推,一直乘,直到\(i\)大于\(m\)为止

因为分子有连续的一段长于\(m\)的整数,所以必定是\(0\)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define R register int
#define int long long
#define scanf Ruusupuu = scanf
#define printf Ruusupuu = printf

int Ruusupuu ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef pair< int , int > PI ;
const int N = 1e5 + 10 ;
const int M = 1e6 + 3 ;
const int P = 166667 + 10 ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ; 
}

inline int qpow( int a , int b ){
	int ans = 1 ; 
	b %= ( M - 1 ) ;
	while( b ){
		if( b & 1 ) ans = ( ans * a ) % M ;
		a = ( a * a ) % M , b >>= 1 ;
	} return ans ;
}

int n , m , k , kk , cs , fz = 1 , ny ; 

void sc(){
	n = read() , m = read() , k = qpow( 2 , n ) ;
}	

inline int count( int x ){
	int ans = 0 , p = x ;
	while( x % 2 == 0 ) x /= 2 , ans ++ ;
//	printf( "%lld %lld\n" , qpow( ny , ans ) , k - p ) ;
	kk = ( ( ( k - p + M ) % M ) * qpow( ny , ans ) ) % M ; 
	return ans ;
}

void work(){
	ny = qpow( 2 , M - 2 ) ;
	int t = 0 ; 
	for( R i = 1 ; i < m ; i ++ ){
		t += count( i ) ;
		fz = ( fz * kk ) % M ;
	} //printf( "%lld\n" , t ) ;
	int fm = ( qpow( ny , t ) * qpow( qpow( 2 , n ) , m - 1 ) ) % M	 ;
	fz = ( fm - fz + M ) % M ;
	printf( "%lld %lld\n" , fz , fm ) ; 	
}

void Work(){
	int t = 2 , zt = 0 , ny = qpow( 2 , M - 2 ) ;
	while( t < m-1 ) { zt += (int)( (m-1) / t ) , t *= 2 ; }
//	printf( "%lld %lld %lld\n" , zt , qpow( ny , zt ) , ny ) ;
	int x = ( qpow( qpow( 2 , n ) , m - 1 ) * qpow( ny , zt ) ) % M ; 
	printf( "%lld %lld\n" , x , x  ) ;
}

signed main(){
	sc() ;
	if( m < M ) work() ;
	else Work() ;
	return 0 ; 
}
posted @ 2021-07-13 06:11  Soresen  阅读(42)  评论(0)    收藏  举报